This is a creation in Article, where the information may have evolved or changed.
The HTTP specification defines a return code to 3xx
represent the client that needs to do some extra work to complete the request, mostly 3xx
for forwarding (redirect).
A detailed description of the status code can refer to the specification or Wikipedia, Wikipedia, the following is a short introduction to the code.
- Multiple Choices: Returns multiple resources to choose from
- 301 Moved Permanently: The requested resource has been permanently moved to a new location, and any future references to this resource should use one of several URIs returned by this response
- 302 Found: The requested resource is now temporarily responding to requests from different URIs. Since such redirects are temporary, the client should continue to send subsequent requests to the original address, meaning in HTTP 1.0,
Moved Temporarily
but many browsers are implemented at 303, so HTTP 1.1 adds 303 and 307 status codes to differentiate between different behaviors
- 303 See other (since http/1.1): The response to the current request can be found on another URI, and the client should access that resource in a get way
- 304 Not Modified (RFC 7232): The requested resource has not changed
- 305 Use proxy (since http/1.1): The requested resource must be accessed through the specified proxy
- 306 Switch Proxy: In the latest version of the specification, the 306 status code is no longer being used
- 307 temporary Redirect (since http/1.1): The requested resource is now temporarily responding to requests from different URIs, and unlike 303, it still uses the original method
- 308 Permanent Redirect (RFC 7538): The requested resource has been permanently moved to a new location, and the new requested method cannot be changed
Go HTTP Library in the implementation of the process is also constantly complete and modify the bug, in version 1.8 resolved the previous version of the implementation of the problem (you can search redirect in Go issues to see the relevant issue). This article combs the knowledge of Redirect in Go so that you know what to do when you encounter a forwarded problem.
The forwarding policy and the default number of forwards.
http. The client contains a CheckRedirect
field that defines the forwarded policy, which is used by default if you do not set it defaultCheckRedirect
:
1234567 |
func (c *client) Checkredirect (req *request, via []*request) error {fn: = C.checkredirectifnil {fn = DEFAULTC Heckredirect}return fn (req, via)} |
This function is called before the forwarding is performed, and you can see that the function returns ERR and no longer forwards.
The first parameter of this function req
is the request that is about to be forwarded, the second parameter via
has been requested by the requests.
12345678910111213141516171819202122 |
for { ... //need to be forwarded { ... Err = C.checkredirect (req, reqs)if err = = erruselastresponse {returnnil}//discard Previous response... if Nil {UE: = Uerr (ERR) UE. (*url. Error). URL = locreturn RESP, UE} } ...} |
The default forwarding policy is to forward up to 10 times, avoiding high forwarding times or dead loops.
123456 |
func defaultcheckredirect (req *request, via []*request) error {Iflen(via) >= {return errors. New ("stopped after redirects")}returnnil} |
If you want to implement a different forwarding strategy, you need to define your own CheckRedirect
.
Forwarding Security
1) When the forwarded request contains a secure information header, such as,,, Authorization
WWW-Authenticate
Cookie
etc. header, if it is cross-domain, these headers will not be copied to the new request.
123456789 |
func string BOOL {switch canonicalheaderkey (headerkey) {case"Authorization" "www-authenticate" "Cookie" "Cookie2": ihost: = Strings. ToLower (initial. Host) Dhost: = Strings. ToLower (dest. Host)return isdomainorsubdomain (Dhost, Ihost)}returntrue} |
2) If a non-empty cookie jar is set, the forward response modifies the value in the cookie jar, but the next time the header is forwarded, the Cookie
headers are processed, ignoring the changed cookie.
When forwarding the ' cookie ' header with a non-nil cookie Jar.
Since Each redirect may mutate the state of the cookie jar,
A redirect may possibly an alter a cookie set in the initial request.
When forwarding the ' Cookie ' header, any mutated cookie would be omitted,
With the expectation, the Jar would insert those mutated cookies
With the updated values (assuming the Origin matches).
If Jar is nil, the initial cookie is forwarded without.
Specifically, you can view makeHeadersCopier
the implementation.
You can see that each time redirect deletes the changes caused by the last redirect, and then restores the coookie of the original request.
1234567891011121314151617181920212223242526272829 |
ifC.jar! =Nil&& icookies! =Nil{varChangedBOOLRESP: = req. Response//The response that caused the upcoming redirect for_, C: =RangeResp. Cookies () {if_, OK: = Icookies[c.name]; OK {Delete(Icookies, c.name) changed =true}}ifChanged {Ireqhdr. Del ("Cookie")varSS []string for_, cs: =Rangeicookies { for_, C: =RangeCS {ss =Append(SS, c.name+"="+c.value)}}sort. Strings (SS)//Ensure deterministic headersIreqhdr. Set ("Cookie", strings. Join (SS,"; "))}}//Copy The initial request ' s Header values//(at least the safe ones). forK, VV: =RangeIREQHDR {ifShouldcopyheaderonredirect (k, Preq. URL, req. URL) {req. HEADER[K] = VV}} |
Forwarding rules
When the server returns a forwarding response, the client first uses the CheckRedirect
function to check whether to forward.
The following requests are processed by default:
- 301 (Moved permanently)
- 302 (Found)
- 303 (see other)
- 307 (Temporary Redirect)
- 308 (Permanent Redirect)
If you need to forward, for,, 301
302
303
The status code, then the forwarded request will convert the request method into GET
method (if the original request method is the HEAD
same, or HEAD
), And the body is empty, although the original request may contain the body. For 307
the 308
status code, the Method of the next forwarded request is unchanged, consistent with the original request, and the original body content is used to send the forwarding request.
The logic of code processing is redirectBehavior
implemented by functions.
1234567891011121314151617181920212223242526 |
funcRedirectbehavior (Reqmethodstring, resp *response, Ireq *request) (Redirectmethodstring, Shouldredirect, IncludebodyBOOL) {SwitchResp. StatusCode { Case301,302,303: Redirectmethod = Reqmethodshouldredirect =trueIncludebody =falseifReqmethod! ="GET"&& Reqmethod! ="HEAD"{Redirectmethod ="GET"} Case307,308: Redirectmethod = Reqmethodshouldredirect =trueIncludebody =trueifResp. Header.get ("Location") ==""{Shouldredirect =false Break}ifIreq. GetBody = =Nil&& ireq.outgoinglength ()! =0{Shouldredirect =false}}returnRedirectmethod, Shouldredirect, includebody} |
The above is an introduction to the HTTP redirect related content, which is mainly the client's code logic. The following two sections describe something that is a little bit related to HTTP redirect.
Redirecthandler
HTTP defines a convenience type: Redirecthandler, which is a predefined HTTP handler that forwards the specified request to the specified URL, primarily using the set URL and status code settings response Locatio N.
It is used as a server-side development.
1 |
func string int) Handler |
Note that code should be 3xx
the status code, usually StatusMovedPermanently
, StatusFound
or StatusSeeOther
.
Roundtripper
Roundtripper is also used as a client development.
The Roundtripper represents an HTTP request. When using redirect, you may redirect multiple times, that is, HTTP requests that execute n times.
123 |
type Interface { roundtrip (*request) (*response, error)} |
DefaultTransport
is the default Roundtripper implementation. It establishes a network connection and caches it for subsequent request reuse. It uses $HTTP_PROXY
and $NO_PROXY
(or $http _proxy, $no _proxy) environment variables to set the proxy.
Other Roundtripper implementations also have the NewFileTransport
Roundtripper created to serve the filesystem and map the file system to HTTP processing.
123456789101112 |
var Defaulttransport roundtripper = &transport{ proxy:proxyfromenvironment, dialcontext: (&net. dialer{ Timeout: * time. Second, KeepAlive: * time. Second, true, }). Dialcontext, Maxidleconns: + , idleconntimeout: * time. Second, tlshandshaketimeout: Ten * time. Second, expectcontinuetimeout: 1 * time. Second,} |
When Redirect
the default forwarding is the HTTP library automatically to help you achieve, if you want to do in-depth tracking of the forwarding process (simple tracking can use HttpTrace), you can customize a roundtripper, such as the following:
Http://stackoverflow.com/questions/24577494/how-to-get-the-http-redirect-status-codes-in-golang
12345678910111213141516171819 |
type struct { Transport http. Roundtripper}func (l logredirects) roundtrip (req *http. Request) (Resp *http. Response, err Error) { T: = L.transport ifnil { t = http. Defaulttransport } resp, err = T.roundtrip (req) ifnil { return } Switch resp. StatusCode {case http. statusmovedpermanently, http. Statusfound, http. Statusseeother, http. Statustemporaryredirect: log. Println ("Request for""redirected with Status", resp. StatusCode) } return} |
Client
You can use the following code when you create it:
1 |
Client: = &http. client{transport:logredirects{}} |
So we can track each forwarding process.