Implement library support for Angular-style single page applications
This commit is contained in:
parent
f08165b0f1
commit
d5b4fcf0be
32
README.md
32
README.md
|
@ -28,3 +28,35 @@ else will be ignored.
|
||||||
The interaction between range handling and compression also seems a little
|
The interaction between range handling and compression also seems a little
|
||||||
ill-defined; as we have pre-compressed data, however, we can consistently
|
ill-defined; as we have pre-compressed data, however, we can consistently
|
||||||
serve the exact same byte data for compressed files.
|
serve the exact same byte data for compressed files.
|
||||||
|
|
||||||
|
## Angular-style single-page application handling
|
||||||
|
|
||||||
|
If you wish to support an angular.js-style single page application, in which
|
||||||
|
a Javascript application uses the browser's history API to create a set of
|
||||||
|
virtual paths ("routes"), it is necessary to somehow intercept HTTP 404 errors
|
||||||
|
being returned from the handler and instead return an HTTP 200 with an HTML
|
||||||
|
document.
|
||||||
|
|
||||||
|
This can be achieved with a number of methods.
|
||||||
|
|
||||||
|
If you have an nginx instance reverse proxying in front of `htpack`, then you
|
||||||
|
can use a couple of extra directives, for example:
|
||||||
|
|
||||||
|
# prevent page loaded at "http://server.example/my-application" from
|
||||||
|
# requesting resources at "/*" when it should request them at
|
||||||
|
# "/my-application/*" instead
|
||||||
|
location = /my-application {
|
||||||
|
return 308 /my-application/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /my-application/ {
|
||||||
|
proxy_to http://htpack-addr:8080/;
|
||||||
|
proxy_intercept_errors on;
|
||||||
|
error_page 404 =200 /my-application/;
|
||||||
|
}
|
||||||
|
|
||||||
|
If you are using the handler as a library, then you may call
|
||||||
|
`handler.SetNotFound(filename)` to select a resource to return (with HTTP 200)
|
||||||
|
if a request is made for a resource that is not found. The filename must match
|
||||||
|
a packed resource, so it will be preceded with a `/` (for example it may be
|
||||||
|
`"/index.html"`).
|
||||||
|
|
30
handler.go
30
handler.go
|
@ -72,6 +72,7 @@ type Handler struct {
|
||||||
dir map[string]*packed.File
|
dir map[string]*packed.File
|
||||||
headers map[string]string
|
headers map[string]string
|
||||||
startTime time.Time
|
startTime time.Time
|
||||||
|
notFound *packed.File
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetHeader allows a custom header to be set on HTTP responses. These are
|
// SetHeader allows a custom header to be set on HTTP responses. These are
|
||||||
|
@ -110,6 +111,28 @@ func (h *Handler) SetIndex(filename string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetNotFound allows overriding the returned resource when a request is made
|
||||||
|
// for a resource that does not exist. The default behaviour would be to return
|
||||||
|
// a standard HTTP 404 Not Found response; calling this function with an empty
|
||||||
|
// string will restore that behaviour.
|
||||||
|
//
|
||||||
|
// This function will return an error if the named resource is not present in
|
||||||
|
// the packfile.
|
||||||
|
func (h *Handler) SetNotFound(notFound string) error {
|
||||||
|
if notFound == "" {
|
||||||
|
h.notFound = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
notFound = path.Clean(notFound)
|
||||||
|
dir := h.dir[path.Clean(notFound)]
|
||||||
|
if dir == nil {
|
||||||
|
return fmt.Errorf("no such resource %q", notFound)
|
||||||
|
}
|
||||||
|
h.notFound = dir
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// ServeHTTP handles requests for files. It supports GET and HEAD methods, with
|
// ServeHTTP handles requests for files. It supports GET and HEAD methods, with
|
||||||
// anything else returning a 405. Exact path matches are required, else a 404 is
|
// anything else returning a 405. Exact path matches are required, else a 404 is
|
||||||
// returned.
|
// returned.
|
||||||
|
@ -130,8 +153,11 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||||
|
|
||||||
info := h.dir[path.Clean(req.URL.Path)]
|
info := h.dir[path.Clean(req.URL.Path)]
|
||||||
if info == nil {
|
if info == nil {
|
||||||
http.NotFound(w, req)
|
if h.notFound == nil {
|
||||||
return
|
http.NotFound(w, req)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
info = h.notFound
|
||||||
}
|
}
|
||||||
|
|
||||||
// set standard headers
|
// set standard headers
|
||||||
|
|
Loading…
Reference in New Issue