dtd793353 2019-03-11 22:06
浏览 324

405方法不允许,并且“ tcpdump说它已发送出去,” CORS标头“ Access-Control-Allow-Origin”丢失了”

This question follows this one so some of the text is the same.

The error message on Firefox console when the front end tries to POST JSON data to the back end upon submitting a form.:

"Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://backend_domain/anteroom. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)."

I'm running the Golang back end with a systemd unit and serving it at localhost:12345. Nginx listens at port 80 and passes requests down to it:

listen 80;
server_name backend_domain;

location / {
    include proxy_params;
    proxy_pass http://localhost:12345/;
}

I'm running the Angular front end as a build (built with --prod flag) using PM2 with angular-http-server serving it at port 8080. Same as the back end, Nginx does its thing from port 80:

listen 80;
server_name frontend_domain;

location / {
    include proxy_params;
    proxy_pass http://localhost:8080/;
}

The versions I'm working with: Ubuntu 16.04, PM2 3.3.1, Angular CLI 7.3.4, angular-http-server 1.8.1.

Firefox's network tab in developer's tools reveals the POST request headers:

Host: backend_domain
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:65.0) Gecko/20100101 Firefox/65.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: frontend_domain/
Content-Type: text/plain
Content-Length: 111
Origin: frontend_domain
DNT: 1
Connection: keep-alive

And the response headers:

HTTP/1.1 405 Method Not Allowed
Server: nginx/1.10.3 (Ubuntu)
Date: Mon, 11 Mar 2019 21:08:24 GMT
Content-Length: 0
Connection: keep-alive
Strict-Transport-Security: max-age=31536000; includeSubDomains

The actual request that's supposed to go to the back end when I hit the submit button is:

if (val.issues && val.age && val.gender) {
      this.profile = JSON.stringify({
        age: val.age,
        gender: val.gender,
        issues: val.issues
      });

      return this.http
        .post(environment.anteroomPOSTURL, this.profile, {
          observe: "response"
        })

Firefox shows this to successfully trigger, with the JSON showing under the Params tab in Network in dev tools.

This response suggests to me that somehow, Nginx is not passing requests down to the back end at port 12345. Otherwise, it would retrieve and pass the headers from the back end shown below in my Golang code back to the front end, right?

I've read that CORS is a server-side issue. So, I've tried enabling it wherever I've a server, that is, in the back end, Nginx, and angular-http-server.

It's enabled in my Golang code:

func anteroom(res http.ResponseWriter, req *http.Request) {
    res.Header().Set("Access-Control-Allow-Origin", "*")
    res.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS")
    res.Header().Set("Access-Control-Allow-Headers", "Content-Type")
    res.Header().Set("Content-Type", "application/json")
...
}

func main() {
    ...
    # Using Gorilla mux router.
    router := mux.NewRouter()
    router.HandleFunc("/anteroom", anteroom).Methods("POST, OPTIONS")
}

This successfully enables CORS in development, where serving Golang is just opening its built binary and Angular is served with ng serve.

The above isn't enough in production. So, I've tried enabling it with angular-http-server. Note the --cors flag at the end:

pm2 start $(which angular-http-server) --name app -- --path /PATH/TO/DIST -p 8080 --cors

I've also tried enabling it in both the back and front end Nginx files (adapted from here):

location / {
proxy_pass http://localhost:8080; # or 12345 if it's the back end conf
if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'Content-Type';
        add_header 'Content-Type' 'application/json';
        return 204;
     }

     if ($request_method = 'POST') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'Content-Type';
        add_header 'Content-Type' 'application/json';
     }

     if ($request_method = 'GET') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'Content-Type';
     }
}
}

Oddly, no matter if the headers are in either Nginx files or not, tcpdump -vvvs 1024 -l -A src host backend_domain | grep 'Access-Control-Allow-Origin:' produces this:

        Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: *
        Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: *
        Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: *
        Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: *
        Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: *
        Access-Control-Allow-Origin: *
Access-Control-Allow-Origin: *

No idea why it repeats 12 times but, anyway, the back end sends the above the moment the front end loads (which means Nginx does successfully pass requests down to port 12345, right?). It doesn't send them when I click the submit button to submit the form. I don't know if this is correct behaviour or if it indicates that something is wrong.

What am I missing?

Update 12 Mar 19, 7.30pm:

As seen above and pointed out by sideshowbarker in the comments, there's a "405 Method Not Allowed" response. I thought at first that this was linked to the CORS issue and also with Nginx. To verify it, I stopped Nginx, and opened my firewall at port 12345 so that I could POST to the Golang back end directly.

To avoid any complication by the same-origin policy, I used cURL to POST from another machine: curl -v -X POST -H 'Content-Type: application/json' -d '{"age":"l","gender":"l","issues":"l"}' http://droplet_IP:12345/anteroom

I got the exact same response: "HTTP/1.1 405 Method Not Allowed".

At this point, my best guess is that the Golang back end isn't allowing POST even though it's explicitly allowed in the code, as seen above. I'm at a loss as to why.

  • 写回答

1条回答 默认 最新

  • dpca4790 2019-03-12 15:58
    关注

    Primarily, the problem is due to this line for Gorilla mux in main() in the Golang code:

    router.HandleFunc("/anteroom", anteroom).Methods("POST, OPTIONS")

    Notice the methods in the back: ("POST, OPTIONS"). This is wrong. It should be ("POST", "OPTIONS"). They must be quoted separately.

    This is different from when we set the methods in the function for the page with net/http: res.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS"). Here, they are quoted together.

    I think there may have been diverse issues but it's been such a tiring journey I remember only this last one now.

    评论

报告相同问题?

悬赏问题

  • ¥15 BP神经网络控制倒立摆
  • ¥20 要这个数学建模编程的代码 并且能完整允许出来结果 完整的过程和数据的结果
  • ¥15 html5+css和javascript有人可以帮吗?图片要怎么插入代码里面啊
  • ¥30 Unity接入微信SDK 无法开启摄像头
  • ¥20 有偿 写代码 要用特定的软件anaconda 里的jvpyter 用python3写
  • ¥20 cad图纸,chx-3六轴码垛机器人
  • ¥15 移动摄像头专网需要解vlan
  • ¥20 access多表提取相同字段数据并合并
  • ¥20 基于MSP430f5529的MPU6050驱动,求出欧拉角
  • ¥20 Java-Oj-桌布的计算