我正在使用Google App Engine来为Hugo生成的(半)静态网站提供服务。我有一个目录" public"所有HTML文件都存储并将被提供的位置。我也有一些服务器端脚本用于联系表单处理。 app.yaml
文件看起来像这样。
// app.yaml
runtime: go
api_version: go1
handlers:
- url: /.*
script: _go_app
secure: always
简化的main.go
文件看起来像这样
// main.go
package main
import (
"net/http"
"encoding/json"
"appengine"
"appengine/urlfetch"
)
func init() {
fileHandler := http.FileServer(http.Dir("public"))
http.Handle("/", fileHandler)
http.HandleFunc("/contactus/", HandleContactus)
}
这非常有效并且可以提供html文件。但是,我正在寻找一种解决方案来处理未找到页面的情况,例如响应为404 Not Found
(或任何其他服务器错误)。
我的想法是创建一个自定义处理程序,可以在http.Handle("/", myCustomHandler)
中传递并处理服务器响应,并在必要时重定向到自定义404.html
等。我是Go的新手,似乎无法弄清楚应如何实施。我也看过Gorilla Mux,但更喜欢(如果可能的话)不使用外部库来保持简单。
基于this post,我尝试了以下
package main
import (
"net/http"
"encoding/json"
"appengine"
"appengine/urlfetch"
)
func StaticSiteHandler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
h.ServeHTTP(w, r)
})
}
func init() {
fileHandler := http.FileServer(http.Dir("public"))
http.Handle("/", StaticSiteHandler(fileHandler))
http.HandleFunc("/contactus/", HandleContactus)
}
此解决方案的工作原理是它也可以为我的HTML页面提供服务,但是我仍然无法弄清楚如何处理服务器响应代码。
任何帮助都将受到高度赞赏。 谢谢!
答案 0 :(得分:3)
为了使中间件与http.FileServer
分离,当您将其包装起来时,您可以传递http.ResponseWriter
的具体实现:
WriteHeader
)WriteHeader
:
Write
调用
WriteHeader
或使用非404调用,则:
ResponseWriter
WriteHeader
和Write
来电转接至真实ResponseWriter
type notFoundInterceptorWriter struct {
rw http.ResponseWriter // set to nil to signal a 404 has been intercepted
h http.Header // set to nil to signal headers have been emitted
notFoundHandler http.Handler
r *http.Request
}
func (rw *notFoundInterceptorWriter) Header() http.Header {
if rw.h == nil && rw.rw != nil {
return rw.rw.Header()
}
return rw.h
}
func (rw *notFoundInterceptorWriter) WriteHeader(status int) {
if status == http.StatusNotFound {
rw.notFoundHandler.ServeHTTP(rw.rw, rw.r)
rw.rw = nil
} else {
for k, vs := range rw.h {
for _, v := range vs {
rw.rw.Header().Add(k, v)
}
}
rw.rw.WriteHeader(status)
}
rw.h = nil
}
func (rw *notFoundInterceptorWriter) Write(b []byte) (int, error) {
if rw.rw != nil {
return rw.rw.Write(b)
}
// ignore, so do as if everything was written OK
return len(b), nil
}
func StaticSiteHandler(h, notFoundHandler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w = ¬FoundInterceptorWriter{
rw: w,
h: make(http.Header),
notFoundHandler: notFoundHandler,
r: r,
}
h.ServeHTTP(w, r)
})
}
答案 1 :(得分:0)
您可以在提供文件之前对其进行统计,以查看其是否存在。根据需要调整404处理程序(发出模板等)
package main
import (
"net/http"
"path"
"os"
)
func init() {
http.Handle("/", staticHandler)
}
func error404Handler(w http.ResponseWriter, r *http.Request) {
http.Error(w, "404 not found", http.StatusNotFound)
}
func staticHandler(w http.ResponseWriter, r *http.Request) {
name := path.Clean(r.URL.Path)
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
error404Handler(w, r)
return
}
http.Error(w, "internal error", http.StatusInternalServerError)
return
}
return http.ServeFile(w, r, name)
}