這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
Keywords: HandlerFunc, RedirectHandler, Redirect
前言
在Go-http-HandlerFunc()函數中,詳細介紹了HandlerFunc,所以本文換個方式來講:從外往裡一層層剝離,即先講使用者層面的API或使用方法,然後再介紹涉及的內部實現細節。
RedirectHandler實現代碼
func Redirect(w ResponseWriter, r *Request, urlStr string, code int) { // Skipped now ...}// Redirect to a fixed URLtype redirectHandler struct { url string code int}func (rh *redirectHandler) ServeHTTP(w ResponseWriter, r *Request) { Redirect(w, r, rh.url, rh.code)}// RedirectHandler returns a request handler that redirects// each request it receives to the given url using the given// status code.//// The provided code should be in the 3xx range and is usually// StatusMovedPermanently, StatusFound or StatusSeeOther.func RedirectHandler(url string, code int) Handler { return &redirectHandler{url, code}}
慣用法
使用者可以看到的介面就是:
func RedirectHandler(url string, code int) Handler
樣本
TODO 待補充
type redirectHandler
上面的原始碼中,給出了type redirectHandler的定義。——redirectHandler也是Handler介面的一個實現。
Redirect()
redirectHandler具體類用到了Redirect()函數,原始碼如下:
// Redirect replies to the request with a redirect to url,// which may be a path relative to the request path.//// The provided code should be in the 3xx range and is usually// StatusMovedPermanently, StatusFound or StatusSeeOther.func Redirect(w ResponseWriter, r *Request, urlStr string, code int) { if u, err := url.Parse(urlStr); err == nil { // If url was relative, make absolute by // combining with request path. // The browser would probably do this for us, // but doing it ourselves is more reliable. // NOTE(rsc): RFC 2616 says that the Location // line must be an absolute URI, like // "http://www.google.com/redirect/", // not a path like "/redirect/". // Unfortunately, we don't know what to // put in the host name section to get the // client to connect to us again, so we can't // know the right absolute URI to send back. // Because of this problem, no one pays attention // to the RFC; they all send back just a new path. // So do we. if u.Scheme == "" && u.Host == "" { oldpath := r.URL.Path if oldpath == "" { // should not happen, but avoid a crash if it does oldpath = "/" } // no leading http://server if urlStr == "" || urlStr[0] != '/' { // make relative path absolute olddir, _ := path.Split(oldpath) urlStr = olddir + urlStr } var query string if i := strings.Index(urlStr, "?"); i != -1 { urlStr, query = urlStr[:i], urlStr[i:] } // clean up but preserve trailing slash trailing := strings.HasSuffix(urlStr, "/") urlStr = path.Clean(urlStr) if trailing && !strings.HasSuffix(urlStr, "/") { urlStr += "/" } urlStr += query } } w.Header().Set("Location", urlStr) w.WriteHeader(code) // RFC 2616 recommends that a short note "SHOULD" be included in the // response because older user agents may not understand 301/307. // Shouldn't send the response for POST or HEAD; that leaves GET. if r.Method == "GET" { note := "<a href=\"" + htmlEscape(urlStr) + "\">" + statusText[code] + "</a>.\n" fmt.Fprintln(w, note) }}var htmlReplacer = strings.NewReplacer( "&", "&", "<", "<", ">", ">", // """ is shorter than """. `"`, """, // "'" is shorter than "'" and apos was not in HTML until HTML5. "'", "'",)func htmlEscape(s string) string { return htmlReplacer.Replace(s)}
待詳細解釋