10

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?

Community
  • 1
  • 1
dopatraman
  • 13,416
  • 29
  • 90
  • 154
  • Is the URL / controller action you are POSTing to actually expecting a POST? – Stuart Mar 29 '16 at 21:56
  • Yes. But even if it wasnt, the request is logged as a GET even before it gets to the server. – dopatraman Mar 29 '16 at 21:59
  • that's weird... have you tried using $resource instead? at least to see what happens... – germanio Mar 29 '16 at 22:02
  • @germanio see my update – dopatraman Mar 29 '16 at 22:41
  • That is weird. Have you tried saving your post object as a variable and then calling $http(postVar).then.... and using the debugger in the console? – Gremash Mar 29 '16 at 22:47
  • Also, have you debugged your server and verified that it is actually a get and not a post hitting your server? What do the headers look like server side? – Gremash Mar 29 '16 at 22:50
  • @Gremash yes to both. Please see my update. – dopatraman Mar 29 '16 at 23:13
  • cool, so that is actually what your server is receiving. How about what the browser is sending? (use dev tools, network tab)... both front and backend are served from the same host:port right? (CORS?) – germanio Mar 29 '16 at 23:26
  • Accept: and Content-Type: are the ones expected right? – germanio Mar 29 '16 at 23:29
  • so here's something else weird i noticed. I set the `content-type` to multipart, but it is not appearing in the request. I thought that was an issue, just one not necessarily related to the method... thoughts? – dopatraman Mar 30 '16 at 00:19
  • Also, yes both client and server are set to the same host and port. – dopatraman Mar 30 '16 at 00:19
  • It seems to me the server is culprit, not your request – user3791775 Mar 30 '16 at 01:00
  • @user3791775 please elaborate. how so? – dopatraman Mar 30 '16 at 02:35
  • Maybe you used `$interceptor` for `$http`? – Stepan Kasyanenko Mar 30 '16 at 05:06
  • 1
    "GET" is the default when there is no method specified in the config object. Look for a request interceptor that is broken and returning an undefined config object. – georgeawg Mar 30 '16 at 06:22
  • @georgeawg Please see my updates – dopatraman Mar 30 '16 at 14:58
  • EOF on client side would mean server has closed the connection. In this case might say that client has closed the connection. Could you put the full logs from server? – Griffin Mar 30 '16 at 15:26
  • @Grif-fin please see updates – dopatraman Mar 30 '16 at 15:32
  • Please try and put a condition (if r.Method == "POST" {...}) to only process the POST before: decoder := json.NewDecoder(r.Body) And ignore any GETs. It looks like client is sending a GET first and a POST is about to come but your server crashes because it tries to decode the GET. – Griffin Mar 30 '16 at 15:37
  • The POST is never logged. – dopatraman Mar 30 '16 at 15:40
  • Could be because it never arrives? Try commenting out the 'panic()' and instead 'return' as a test – Griffin Mar 30 '16 at 15:41
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/107756/discussion-between-grif-fin-and-dopatraman). – Griffin Mar 30 '16 at 15:42
  • I think as you have got your answer from [here](http://stackoverflow.com/questions/36316429/go-web-server-is-automatically-redirecting-post-requests) worth sharing it. – Griffin Mar 30 '16 at 18:52
  • I had this same problem when mistakenly adding double slash to my request URL e.g. `localhost:5432//register` instead of `localhost:5432/register` – Frank May 02 '20 at 03:42

2 Answers2

10

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:

Go web server is automatically redirecting POST requests

You can read more on the subject here:

Why doesn't HTTP have POST redirect?

Community
  • 1
  • 1
icza
  • 389,944
  • 63
  • 907
  • 827
0

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[p]));
                return str.join("&");
            },
            data: {
                LoginForm_Login: userData.username,
                LoginForm_Password: userData.password
            },
            url: YOURURL
        }).then(
Tom
  • 1
  • 2
  • 2
    While this code may solve the asker's problem, it would be preferable to explain how it works and what are the differences between it and what the asker has tried (if (s)he has tried anything at all). – The SE I loved is dead Oct 09 '16 at 23:17