在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
在之前我写过一篇关于通过使用
我以前的方法中使用了 func SomeHandler(w http.ResponseWriter, r *http.Request) (int, error) { db, err := someDBcall() if err != nil { // This makes sense. return 500, err } if user.LoggedIn { http.Redirect(w, r, "/dashboard", 302) // Superfluous! Our http.Redirect function handles the 302, not // our return value (which is effectively ignored). return 302, nil } } 看起来还行,但是我们可以做的更好 一些区别那么我们应该如何改进它?我们先列出代码: package handler // Error represents a handler error. It provides methods for a HTTP status // code and embeds the built-in error interface. type Error interface { error Status() int } // StatusError represents an error with an associated HTTP status code. type StatusError struct { Code int Err error } // Allows StatusError to satisfy the error interface. func (se StatusError) Error() string { return se.Err.Error() } // Returns our HTTP status code. func (se StatusError) Status() int { return se.Code } // A (simple) example of our application-wide configuration. type Env struct { DB *sql.DB Port string Host string } // The Handler struct that takes a configured Env and a function matching // our useful signature. type Handler struct { *Env H func(e *Env, w http.ResponseWriter, r *http.Request) error } // ServeHTTP allows our Handler type to satisfy http.Handler. func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { err := h.H(h.Env, w, r) if err != nil { switch e := err.(type) { case Error: // We can retrieve the status here and write out a specific // HTTP status code. log.Printf("HTTP %d - %s", e.Status(), e) http.Error(w, e.Error(), e.Status()) default: // Any error types we don't specifically look out for default // to serving a HTTP 500 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } } } 上面的代码不言自明,但是要说明一下一些突出的观点:
如果我们不想捕捉那些错误,那么 所有示例它最后是什么样子的?我们是否可以将其分到不同的包中? package handler import ( "net/http" ) // Error represents a handler error. It provides methods for a HTTP status // code and embeds the built-in error interface. type Error interface { error Status() int } // StatusError represents an error with an associated HTTP status code. type StatusError struct { Code int Err error } // Allows StatusError to satisfy the error interface. func (se StatusError) Error() string { return se.Err.Error() } // Returns our HTTP status code. func (se StatusError) Status() int { return se.Code } // A (simple) example of our application-wide configuration. type Env struct { DB *sql.DB Port string Host string } // The Handler struct that takes a configured Env and a function matching // our useful signature. type Handler struct { *Env H func(e *Env, w http.ResponseWriter, r *http.Request) error } // ServeHTTP allows our Handler type to satisfy http.Handler. func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { err := h.H(h.Env, w, r) if err != nil { switch e := err.(type) { case Error: // We can retrieve the status here and write out a specific // HTTP status code. log.Printf("HTTP %d - %s", e.Status(), e) http.Error(w, e.Error(), e.Status()) default: // Any error types we don't specifically look out for default // to serving a HTTP 500 http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) } } } func GetIndex(env *Env, w http.ResponseWriter, r *http.Request) error { users, err := env.DB.GetAllUsers() if err != nil { // We return a status error here, which conveniently wraps the error // returned from our DB queries. We can clearly define which errors // are worth raising a HTTP 500 over vs. which might just be a HTTP // 404, 403 or 401 (as appropriate). It's also clear where our // handler should stop processing by returning early. return StatusError{500, err} } fmt.Fprintf(w, "%+v", users) return nil } package main import ( "net/http" "github.com/you/somepkg/handler" ) func main() { db, err := sql.Open("connectionstringhere") if err != nil { log.Fatal(err) } // Initialise our app-wide environment with the services/info we need. env := &handler.Env{ DB: db, Port: os.Getenv("PORT"), Host: os.Getenv("HOST"), // We might also have a custom log.Logger, our // template instance, and a config struct as fields // in our Env struct. } // Note that we're using http.Handle, not http.HandleFunc. The // latter only accepts the http.HandlerFunc type, which is not // what we have here. http.Handle("/", handler.Handler{env, handler.GetIndex}) // Logs the error if ListenAndServe fails. log.Fatal(http.ListenAndServe(":8000", nil)) } |
请发表评论