我想對 POST 請求使用相同的正文進行重定向。
來自 GO 源 (client.go)
func redirectBehavior(reqMethod string, resp *Response, ireq *Request) (redirectMethod string, shouldRedirect, includeBody bool) {
switch resp.StatusCode {
case 301, 302, 303:
redirectMethod = reqMethod
shouldRedirect = true
includeBody = false
// RFC 2616 allowed automatic redirection only with GET and
// HEAD requests. RFC 7231 lifts this restriction, but we still
// restrict other methods to GET to maintain compatibility.
// See Issue 18570.
但有時服務器會為 POST 請求回傳 302 Redirect,這意味著我需要將相同的正文發送到另一個位置。
在這種情況下我該怎么辦?
func FollowRedirectForPost() {
client := &http.Client{}
req, _ := http.NewRequest(http.MethodPost, "example.com/test", strings.NewReader(url.Values{
"key": {"value"},
"key1":{"value1"},
}.Encode()))
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
client.Do(req) // If server returns 302 Redirect so it means I need make the same request with the same body to
// a different location. Just imagine i replaced "example.com/test" to "example.com/redirect_url"
}
uj5u.com熱心網友回復:
來自RFC7231:
服務器應該在回應中生成一個 Location 頭欄位,其中包含不同 URI 的 URI 參考。用戶代理可以使用 Location 欄位值進行自動重定向。服務器的回應負載通常包含一個簡短的超文本注釋,其中包含指向不同 URI 的超鏈接。
注意:由于歷史原因,用戶代理可能會將請求方法從 POST 更改為 GET 以用于后續請求。如果不希望出現此行為,則可以改用 307(臨時重定向)狀態代碼。
所以你可以跟隨重定向,新的 URI 在Location標題中。你不必。您可以將方法更改為 GET,但不必如此。所以本質上,您所做的任何事情都符合 RFC。
您可以通過提供CheckRedirect函式來提供自己的重定向策略。redirectPostOn302基本上與客戶端所做的相同,如果includeBody是true和redirectMethod是POST:
func FollowRedirectForPost() {
client := &http.Client{
CheckRedirect: redirectPostOn302,
}
req, _ := http.NewRequest(http.MethodPost, "example.com/test", strings.NewReader(url.Values{
"key": {"value"},
"key1":{"value1"},
}.Encode()))
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
client.Do(req) // If server returns 302 Redirect so it means I need make the same request with the same body to
// a different location. Just imagine i replaced "example.com/test" to "example.com/redirect_url"
}
func redirectPostOn302(req *http.Request, via []*http.Request) error {
if len(via) >= 10 {
return errors.New("stopped after 10 redirects")
}
lastReq := via[len(via)-1]
if req.Response.StatusCode == 302 && lastReq.Method == http.MethodPost {
req.Method = http.MethodPost
// Get the body of the original request, set here, since req.Body will be nil if a 302 was returned
if via[0].GetBody != nil {
var err error
req.Body, err = via[0].GetBody()
if err != nil {
return err
}
req.ContentLength = via[0].ContentLength
}
}
return nil
}
uj5u.com熱心網友回復:
最佳做法是更改服務器狀態代碼 - 307(臨時重定向)或 308(永久重定向)。
如果服務器回復重定向,則客戶端首先使用 CheckRedirect 函式來確定是否應該遵循重定向。如果允許,301、302 或 303 重定向會導致后續請求使用 HTTP 方法 GET(如果原始請求是 HEAD,則為 HEAD),沒有正文。307 或 308 重定向保留原始 HTTP 方法和正文,前提是定義了 Request.GetBody 函式。NewRequest 函式會自動為常見的標準庫主體型別設定 GetBody。
另一種超級hacky方法可能是 - 更改 CheckRedirect 函式中的請求 https://github.com/golang/go/blob/master/src/net/http/client.go#L78 https://github.com/golang/ go/blob/master/src/net/http/client.go#L691
// example hack
func FollowRedirectForPost(data io.Reader) {
client := &http.Client{
CheckRedirect: func(req *Request, via []*Request) error {
// check status code etc.
req.Method = http.MethodPost
req.Body = data
}
}
req, _ := http.NewRequest(http.MethodPost, "example.com/test", data)
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
client.Do(req) // If server returns 302 Redirect so it means I need make the same request with the same body to
// a different location. Just imagine i replaced "example.com/test" to "example.com/redirect_url"
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/400791.html
上一篇:Docker GolangHTTPS問題。OpenSSLSSL_connect:SSL_ERROR_SYSCALL
