$http.post()方法实际上发送的是GET请求。

huangapple go评论73阅读模式
英文:

$http.post() method is actally sending a GET

问题

##注意:
我发现了一个可能相关的问题,需要提一个新问题在这里


这是一个奇怪的问题。我在过去的两年中一直在使用Angular,从未遇到过这个问题。

我正在使用Angular v1.5.0。我像这样发送一个POST请求:

$http({
    method: "POST",
    url: "/myurl",
    data: {
        file: myFile // 这只是一个对象
    }
});

很普通的POST请求,对吧?但是问题来了。我查看控制台和网络选项卡,发现请求被记录为GET请求。非常奇怪。所以我尝试修改代码,像这样工作:

$http.post("/myurl", {file: myFile});

结果还是一样。在逐步调试$http服务代码后,我确信头部信息被正确设置了。还有其他人遇到过这个问题吗?

#更新
根据germanio的建议,我尝试使用$resource服务:

promise = $resource("/upload").save()

(由于其他原因,这会返回一个错误,但仍然正确执行POST请求)。我遇到了同样的问题:请求在控制台中被记录为GET请求。

当请求到达我的服务器时,以下是请求的头部信息:

GET /myurl/ HTTP/1.1
Host: localhost:8001
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Cache-Control: no-cache
Connection: keep-alive
Pragma: no-cache
Referer: http://localhost:8001/myurl/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36

#更新2
根据georgeawg的建议,我使用拦截器记录了请求的各个阶段。以下是拦截器的代码:

$httpProvider.interceptors.push(function() {
    return {
        request: function(config) {
            console.log(config);
            return config;
        }
    }
}

运行这段代码后,我得到了以下日志:

data:Object // 包含文件对象
headers: Object // Content-Type设置为multipart
method:"POST" // ???
url :"/myurl"

这意味着请求是从Angular内部以POST方式发送的,但在浏览器和服务器上仍然被记录为GET请求。我认为这里有一些关于HTTP协议的底层问题我不理解。

请求在实际被浏览器记录之前是否已发送到服务器?如果是这样,至少可能指向我的服务器有问题。

为了找出问题所在,这是我的服务器代码:

type FormStruct struct {
    Test string
}

func PHandler(w http.ResponseWriter, r *http.Request) {
    var t FormStruct

    req, _ := httputil.DumpRequest(r, true)
    
    log.Println(string(req))
    log.Println(r.Method) // GET
    log.Println(r.Body)
    
    decoder := json.NewDecoder(r.Body)
    err := decoder.Decode(&t)
    log.Println("Decoding complete")
    if err != nil {
        log.Println("Error")
        panic(err.Error()+"\n\n")
    }
    log.Println(t.Test)

    w.Write([]byte("Upload complete, no errors"))
}

func main() {
    http.HandleFunc("/myurl/", PHandler)    
    fmt.Println("Go Server listening on port 8001")
    http.ListenAndServe(":8001", nil)
}

当服务器接收到请求时,会抛出EOF错误:

2016/03/30 10:51:37 http: panic serving [::1]:52039: EOF

在这个上下文中,EOF是什么意思都不清楚。

#更新3
根据另一个用户的建议,我尝试使用POSTMAN发送一个伪造的POST请求到我的服务器。服务器正确接收到了请求。这对我来说意味着Angular发送POST请求时出了问题。请帮忙解决。

有什么想法吗?

完整的服务器日志:

Go Server listening on port 8001

2016/03/30 11:13:08 GET /myurl/ HTTP/1.1
Host: localhost:8001
Accept: */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Cache-Control: no-cache
Connection: keep-alive
Content-Type: application/json
Postman-Token: 33d3de90-907e-4350-c703-6c57a4ce4ac0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36
X-Xsrf-Token: null

2016/03/30 11:13:08 GET
2016/03/30 11:13:08 {}
2016/03/30 11:13:08 Decoding complete
2016/03/30 11:13:08 Error
2016/03/30 11:13:08 http: panic serving [::1]:52228: EOF

goroutine 5 [running]:
net/http.(*conn).serve.func1(0xc820016180)
	/usr/local/Cellar/go/1.6/libexec/src/net/http/server.go:1389 +0xc1
panic(0x3168c0, 0xc82000b1a0)
	/usr/local/Cellar/go/1.6/libexec/src/runtime/panic.go:426 +0x4e9
routes.FUPHandler(0x1055870, 0xc820061ee0, 0xc820104000)
	/Users/projectpath/routes.go:42 +0x695
net/http.HandlerFunc.ServeHTTP(0x4e7e20, 0x1055870, 0xc820061ee0, 0xc820104000)
	/usr/local/Cellar/go/1.6/libexec/src/net/http/server.go:1618 +0x3a
net/http.(*ServeMux).ServeHTTP(0xc820014b40, 0x1055870, 0xc820061ee0, 0xc820104000)
	/usr/local/Cellar/go/1.6/libexec/src/net/http/server.go:1910 +0x17d
net/http.serverHandler.ServeHTTP(0xc820016100, 0x1055870, 0xc820061ee0, 0xc820104000)
	/usr/local/Cellar/go/1.6/libexec/src/net/http/server.go:2081 +0x19e
net/http.(*conn).serve(0xc820016180)
	/usr/local/Cellar/go/1.6/libexec/src/net/http/server.go:1472 +0xf2e
created by net/http.(*Server).Serve
	/usr/local/Cellar/go/1.6/libexec/src/net/http/server.go:2137 +0x44e

#更新4

我偶然发现了一些有趣的事情:

当我向myurl发送POST请求时,Charles记录了一个POST请求,但响应状态是301。之后记录了一个GET请求,这个GET请求正是发送到我的服务器的请求。

正如你在上面看到的,我的服务器没有进行任何重定向。那么这个301是怎么发生的呢?

英文:

##NOTE:
I've found a possibly related issue that warrants a new question here


This is a weird problem. I've been using angular over the course of 2 years and have never run into this problem.

I'm using angular v1.5.0. I'm making a post request like this:

$http({
    method: "POST",
    url: "/myurl",
    data: {
        file: myFile // This is just an object
    }
});

Run-of-the-mill POST request right? Get this. I look in the console and the Network tab logs the request as a GET. Bizarre. So I've jiggered the code to work like this:

$http.post("/myurl", {file: myFile});

Same thing. After stepping through the $http service code I'm confident that the headers are being set properly. Has anyone else run into this problem?

#Update
Taking germanio's advice, i've tried using the $resource service instead:

promise = $resource("/upload").save()

(this returns an error for another reason, it still executes the POST properly). I'm having the same problem: the request is logged as a GET in the console.

Here are the headers of the request when it gets to my server:

GET /myurl/ HTTP/1.1
Host: localhost:8001
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Cache-Control: no-cache
Connection: keep-alive
Pragma: no-cache
Referer: http://localhost:8001/myurl/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36

#Update 2
As per georgeawg's suggestion I've used an interceptor to log the request at its various stages. Here is the interceptor code:

$httpProvider.interceptors.push(function() {
    return {
        request: function(config) {
            console.log(config);
            return config;
        }
    }
}

Having run this code I get this logged:

data:Object // contains file object
headers: Object // has Content-Type set to multipart
method:"POST" // ???
url :"/myurl

So this means the request is being sent as a POST from within Angular, but it is still logged as a GET both in the browser and on my server. I think there is something low level at work here about the HTTP protocol that I dont understand.

Is the request sent to the server before it is actually logged in the browser? If so, that might atleast point to my server as the culprit.

In the hopes of finding out whats going on, here is my server code:

type FormStruct struct {
    Test string
}

func PHandler(w http.ResponseWriter, r *http.Request) {
    var t FormStruct

    req, _ := httputil.DumpRequest(r, true)
    
    log.Println(string(req))
    log.Println(r.Method) // GET
    log.Println(r.Body)
    
    decoder := json.NewDecoder(r.Body)
    err := decoder.Decode(&t)
    log.Println("Decoding complete")
    if err != nil {
        log.Println("Error")
        panic(err.Error()+"\n\n")
    }
    log.Println(t.Test)

    w.Write([]byte("Upload complete, no errors"))
}

func main() {
    http.HandleFunc("/myurl/", PHandler)    
    fmt.Println("Go Server listening on port 8001")
    http.ListenAndServe(":8001", nil)
}

My server throws an EOF error when it receives the request:

2016/03/30 10:51:37 http: panic serving [::1]:52039: EOF

Not sure what an EOF would even mean in this context.

#Update 3
By the suggestion of another use, I tried using POSTMAN to hit my server with a fake POST request. The server receives the request properly. This means to me that there is something up with how angular is making the POST request. Please help.

Any ideas?

Full server logs:

Go Server listening on port 8001

2016/03/30 11:13:08 GET /myurl/ HTTP/1.1
Host: localhost:8001
Accept: */*
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Cache-Control: no-cache
Connection: keep-alive
Content-Type: application/json
Postman-Token: 33d3de90-907e-4350-c703-6c57a4ce4ac0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36
X-Xsrf-Token: null

2016/03/30 11:13:08 GET
2016/03/30 11:13:08 {}
2016/03/30 11:13:08 Decoding complete
2016/03/30 11:13:08 Error
2016/03/30 11:13:08 http: panic serving [::1]:52228: EOF

goroutine 5 [running]:
net/http.(*conn).serve.func1(0xc820016180)
	/usr/local/Cellar/go/1.6/libexec/src/net/http/server.go:1389 +0xc1
panic(0x3168c0, 0xc82000b1a0)
	/usr/local/Cellar/go/1.6/libexec/src/runtime/panic.go:426 +0x4e9
routes.FUPHandler(0x1055870, 0xc820061ee0, 0xc820104000)
	/Users/projectpath/routes.go:42 +0x695
net/http.HandlerFunc.ServeHTTP(0x4e7e20, 0x1055870, 0xc820061ee0, 0xc820104000)
	/usr/local/Cellar/go/1.6/libexec/src/net/http/server.go:1618 +0x3a
net/http.(*ServeMux).ServeHTTP(0xc820014b40, 0x1055870, 0xc820061ee0, 0xc820104000)
	/usr/local/Cellar/go/1.6/libexec/src/net/http/server.go:1910 +0x17d
net/http.serverHandler.ServeHTTP(0xc820016100, 0x1055870, 0xc820061ee0, 0xc820104000)
	/usr/local/Cellar/go/1.6/libexec/src/net/http/server.go:2081 +0x19e
net/http.(*conn).serve(0xc820016180)
	/usr/local/Cellar/go/1.6/libexec/src/net/http/server.go:1472 +0xf2e
created by net/http.(*Server).Serve
	/usr/local/Cellar/go/1.6/libexec/src/net/http/server.go:2137 +0x44e

#Update 4

I stumbled onto something interesting:

Charles logs a POST request when I post to myurl, but the response status is 301. After the POST a GET is logged. This is the GET that is hitting my server.

My server, as you can see above, does not do any sort of redirection. How is the 301 happening?

答案1

得分: 10

这是由于安全考虑。

在您的情况下,当服务器向浏览器发送重定向时,浏览器不会重复发送POST请求,而只会发送一个“简单”的GET请求。

一般来说,浏览器不会将POST数据发送到重定向的URL,因为浏览器没有资格决定您是否愿意将相同的数据发送到新的URL,就像您打算发送到原始URL的密码、信用卡号码和其他敏感数据一样。但不要试图规避它,只需使用您处理程序的注册路径进行POST,或者使用链接答案中提到的其他提示。

有关上下文,请参阅问题:

https://stackoverflow.com/questions/36316429/go-web-server-is-automatically-redirecting-post-requests

您可以在此处阅读更多相关主题:

为什么HTTP没有POST重定向?

英文:

This is due to a security consideration.

In your situation when a redirect is sent back from the server to the browser, the browser will not repeat the POST request (but rather just a "simple" GET request).

Generally speaking a browser will not send POST data to a redirect URL because the browser is not qualified to decide if you're willing to send the same data to the new URL what you intended to send to the original URL (think about passwords, credit card numbers and other sensitive data). But don't try to circumvent it, simply use registered path of your handler to POST to, or any of the other tips mentioned in the linked answer.

For context see question:

https://stackoverflow.com/questions/36316429/go-web-server-is-automatically-redirecting-post-requests

You can read more on the subject here:

Why doesn't HTTP have POST redirect?

答案2

得分: 0

这段代码实际上向服务器发送了一个GET请求:

$http({
    method: 'POST',
    params: {
        LoginForm_Login: userData.username,
        LoginForm_Password: userData.password
    },
    url: YOURURL
}).then(

你需要使用transformRequest,下面是一个实际发送POST请求的示例:

$http({
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    transformRequest: function (obj) {
        var str = [];
        for (var p in obj)
            str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
        return str.join("&");
    },
    data: {
        LoginForm_Login: userData.username,
        LoginForm_Password: userData.password
    },
    url: YOURURL
}).then(
英文:

This code actually send GET to server

$http({
            method: 'POST',            
            params: {
                LoginForm_Login: userData.username,
                LoginForm_Password: userData.password
            },
            url: YOURURL
        }).then(

You need to use transformRequest, sample below actually send POST

$http({
            method: 'POST',
            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            transformRequest: function (obj) {
                var str = [];
                for (var p in obj)
                    str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj

)); return str.join("&"); }, data: { LoginForm_Login: userData.username, LoginForm_Password: userData.password }, url: YOURURL }).then(

huangapple
  • 本文由 发表于 2016年3月30日 05:51:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/36295758.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定