Go-HTTP-RedirectHandler

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 URL
type 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(
    "&", "&amp;",
    "<", "&lt;",
    ">", "&gt;",
    // "&#34;" is shorter than "&quot;".
    `"`, "&#34;",
    // "&#39;" is shorter than "&apos;" and apos was not in HTML until HTML5.
    "'", "&#39;",
)

func htmlEscape(s string) string {
    return htmlReplacer.Replace(s)
}

待详细解释

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值