405 Метод не разрешен и «отсутствует заголовок CORS« Access-Control-Allow-Origin », хотя tcpdump говорит, что он отправляется - PullRequest
0 голосов
/ 12 марта 2019

Этот вопрос следует за этим один , поэтому часть текста такая же.

Сообщение об ошибке в консоли Firefox, когда внешний интерфейс пытается отправить данные JSON на внутренний сервер после отправки формы .:

«Запрос перекрестного источника заблокирован: та же политика происхождения запрещает чтение удаленного ресурса на https://backend_domain/anteroom. (причина: отсутствует заголовок CORS« Access-Control-Allow-Origin »).»

Я запускаю серверную часть Golang с модулем systemd и обслуживаю его на локальном хосте: 12345. Nginx прослушивает порт 80 и передает ему запросы:

listen 80;
server_name backend_domain;

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

Я запускаю внешний интерфейс Angular как сборку (построенную с флагом --prod), используя PM2 с сервером angular-http, обслуживающим его через порт 8080. Как и серверная часть, Nginx выполняет свою работу из порта 80:

listen 80;
server_name frontend_domain;

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

Версии, с которыми я работаю: Ubuntu 16.04, PM2 3.3.1, Angular CLI 7.3.4, angular-http-server 1.8.1.

На вкладке сети Firefox в инструментах разработчика отображаются заголовки запросов POST:

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

И заголовки ответа:

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

Фактический запрос, который должен перейти на сервер, когда я нажму кнопку отправки:

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 показывает, что это срабатывает успешно, при этом JSON отображается на вкладке Params в Network в dev tools.

Этот ответ подсказывает мне, что каким-то образом Nginx не передает запросы на серверную часть через порт 12345. В противном случае он будет извлекать и передавать заголовки из серверной части, показанной ниже в моем коде Golang, обратно во внешний интерфейс, право?

Я читал, что CORS - это проблема на стороне сервера. Итак, я попытался включить его везде, где у меня есть сервер, то есть на внутреннем сервере Nginx и angular-http-server.

Это включено в моем коде Голанга:

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")
}

Это успешно включает CORS в разработке, где обслуживающий Golang просто открывает свой встроенный двоичный файл, а Angular обслуживается с ng serve.

Выше не хватает в производстве. Итак, я попытался включить его с помощью angular-http-server. Обратите внимание на флаг --cors в конце:

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

Я также попытался включить его в файлах Nginx на задней и передней частях (адаптировано с здесь ):

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';
     }
}
}

Как ни странно, независимо от того, находятся ли заголовки в файлах Nginx или нет, tcpdump -vvvs 1024 -l -A src host backend_domain | grep '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: *
Access-Control-Allow-Origin: *

Понятия не имею, почему он повторяется 12 раз, но, во всяком случае, серверная часть отправляет вышеуказанное в тот момент, когда загружается интерфейсная сторона (что означает, что Nginx успешно передает запросы на порт 12345, верно?). Он не отправляет их, когда я нажимаю кнопку отправки, чтобы отправить форму. Я не знаю, является ли это правильным поведением или это указывает на то, что что-то не так.

Чего мне не хватает?

Обновление 12 марта, 19:30:

Как видно выше и указано сайдшоу в комментариях, есть ответ "Метод 405 не разрешен". Сначала я подумал, что это связано с проблемой CORS, а также с Nginx. Чтобы проверить это, я остановил Nginx и открыл брандмауэр на порту 12345, чтобы я мог напрямую отправлять сообщения на серверную часть Golang.

Чтобы избежать каких-либо осложнений из-за политики того же происхождения, я использовал cURL to POST с другого компьютера: curl -v -X POST -H 'Content-Type: application/json' -d '{"age":"l","gender":"l","issues":"l"}' http://droplet_IP:12345/anteroom

Я получил точно такой же ответ: «HTTP / 1.1 405 Метод не разрешен».

На данный момент, я предпочитаю, что серверная часть Golang не разрешает POST, даже если это явно разрешено в коде, как показано выше. Я в недоумении, почему.

1 Ответ

0 голосов
/ 12 марта 2019

В первую очередь проблема связана с этой строкой для Gorilla mux в main() в коде Голанга:

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

Обратите внимание на методы сзади: ("POST, OPTIONS"). Это не верно. Это должно быть ("POST", "OPTIONS"). Они должны быть указаны отдельно.

Это отличается от того, когда мы устанавливаем методы в функции для страницы с помощью net / http: res.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS"). Здесь они указаны вместе.

Я думаю, что, возможно, были разные проблемы, но это было такое утомительное путешествие, что я помню только последнее.

...