为什么去http发布会获得与curl发布不同的结果?

时间:2019-07-18 14:01:40

标签: go

我正在尝试实现Rest API登录过程。我已经用curl验证了该过程。

使用curl,以下命令将进行登录:

$ curl -i -X POST  https://the-service.mycompany.com/login -d username=<my username> -d password=<mypassword>
HTTP/1.1 200 Connection established

HTTP/1.1 302
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT, PATCH
Access-Control-Max-Age: 3600
Access-Control-Allow-Headers: x-requested-with, content-type, authorization, X-RateLimit-App, X-Spinnaker-Priority
Access-Control-Expose-Headers: X-AUTH-REDIRECT-URL
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Set-Cookie: SESSION=ODdmNGZjZmEtY2EwOC00YzA4LWFmMmYtMjAwNDI1ODM2NjI3; Path=/; HttpOnly; SameSite=Lax
Location: http://the-service.mycompany.com
Content-Length: 0
Date: Thu, 18 Jul 2019 14:38:40 GMT

此命令将成功执行并返回cookie作为响应。

但是当我尝试使用Go代码时:

http := http.Client{
}

const body = "username=myuser&password=mypass"
req, err := http.NewRequest("POST", "https://the-service.mycompany.com/login", strings.NewReader(body))
req.Header.Add("Accept", "*/*")
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Del("Accept-Encoding")
dump, err := httputil.DumpRequestOut(req, true)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("%q\n", dump)

resp, err := client.Do(req)

dump, err = httputil.DumpRequestOut(resp.Request, true)
if err != nil {
    log.Fatal(err)
}
fmt.Printf("%q\n", dump)

fmt.Println("Dump response ==================")
fmt.Println(resp.Status)
for k, v := range resp.Header {
    fmt.Printf("%s: %s\n", k, v)
}

它返回的响应与curl得到的响应不同,这意味着响应头和主体完全不同。

我注意到curl返回两个状态代码200和302。但是go代码的resp.Status是200。

go代码输出为:

"POST /login HTTP/1.1\r\nHost: the-service.mycompany.com\r\nUser-Agent: Go-http-client/1.1\r\nContent-Length: 36\r\nAccept: */*\r\nContent-Type: application/x-www-form-urlencoded\r\nAccept-Encoding: gzip\r\n\r\nusername=myuser&password=mypass"
"GET /login HTTP/1.1\r\nHost: the-service.mycompany.com\r\nUser- Agent: Go-http-client/1.1\r\nAccept: */*\r\nContent-Type: application/x-www-form-urlencoded\r\nReferer: http://the-service.mycompany.com/login\r\nAccept-Encoding: gzip\r\n\r\n"
Dump response ==================
200 
Access-Control-Allow-Origin: [*]
Access-Control-Max-Age: [3600]
Cache-Control: [no-cache, no-store, max-age=0, must-revalidate]
Date: [Thu, 18 Jul 2019 14:53:07 GMT]
Access-Control-Allow-Credentials: [true]
Content-Type: [text/html;charset=UTF-8]
X-Xss-Protection: [1; mode=block]
Pragma: [no-cache]
X-Frame-Options: [DENY]
X-Content-Type-Options: [nosniff]
Access-Control-Allow-Headers: [x-requested-with, content-type, authorization, X-RateLimit-App, X-Spinnaker-Priority]
Access-Control-Expose-Headers: [X-AUTH-REDIRECT-URL]
Expires: [0]
Content-Length: [1324]
Access-Control-Allow-Methods: [POST, GET, OPTIONS, DELETE, PUT, PATCH]

从输出开始,在发送之前,请求是POST,但是当我转储resp.Request时,请求变成了GET,为什么?

1 个答案:

答案 0 :(得分:2)

最后,我找出了问题所在。让我做一个自我回答,希望它对将来遇到类似问题的人有所帮助。

实际上,就我而言,curl不会自动重定向,因为我没有将-L选项与curl一起使用。但是go POST可以自动重定向。

所以我添加了一个CheckRedirect函数来阻止重定向:

func check(req *http.Request, via []*http.Request) error {
    return http.ErrUseLastResponse
}

... in main() ...

    client := http.Client {
        CheckRedirect: check,
    }

然后client.PostForm返回与curl得到的结果相同的302结果。