Приложение Flask, размещенное на CherryPy: OPTIONS возвращает 404

У меня есть restful API, созданный с использованием Flask и Flask-Restful. Все отлично работает на сервере разработки. Все маршруты указаны в Blueprint, хотя конкретный маршрут, с которым мы здесь имеем дело, не является Flask-Restful. Это просто нормальный маршрут Flask.

Я также использую Flask-CORS.

Для развертывания все докеризовано, и я использую CherryPy в качестве хоста WSGI. Таким образом, приложение CherryPy размещает приложение Flask в контейнере. Я использую Traefik в качестве обратного прокси в другом контейнере.

Если я сделаю следующий запрос в Chrome, вставив URL-адрес, запрос GET сработает:

https://api.my-app.new/api/admin/user?_end=10&_order=DESC&_sort=id&_start=0

Однако, если я попытаюсь сделать тот же GET-запрос из приложения React, будет сделан предварительный запрос OPTIONS, и он завершится неудачно с 404. Я проследил его как можно лучше в PyCharm, и проблема, похоже, заключается в следующий код в app.py Flask:

def preprocess_request(self):
    bp = _request_ctx_stack.top.request.blueprint

В принципе, план не найден.

Что на самом деле отправляется, видно из этого вызова curl:

curl 'https://api.my-app.new/api/admin/user?_end=10&_order=DESC&_sort=id&_start=0' \
     -X OPTIONS -H 'access-control-request-method: GET' -H 'origin: https://admin.my-app.new' \
     -H 'accept-encoding: gzip, deflate, br' -H 'accept-language: en-US,en;q=0.9' \
     -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36' \
     -H 'accept: */*' -H 'referer: https://admin.my-app.new/' -H 'authority: api.my-app.new' \
     -H 'access-control-request-headers: authorization,content-type' --compressed

И если я распечатываю заголовки, полученные приложением Flask (в @app.before_request), я получаю следующее:

[2018-01-25 04:31:48,438] INFO - X-Forwarded-Server: cb5d56692c6d
Referer: https://admin.my-app.new/
Accept-Language: en-US,en;q=0.9
Origin: https://admin.my-app.new
X-Real-Ip: 172.19.0.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
Access-Control-Request-Headers: authorization,content-type
X-Forwarded-Proto: https
Host: api.my-app.new
Accept: */*
Access-Control-Request-Method: GET
X-Forwarded-Host: api.my-app.new
X-Forwarded-For: 172.19.0.1
X-Forwarded-Port: 443
Accept-Encoding: gzip, deflate, br

[2018-01-25 04:31:48,440] INFO - Error 404:/api/admin/user?_end=10&_order=DESC&_sort=id&_start=0: 404 Not Found: The requested URL was not found on the server.  If you entered the URL manually please check your spelling and try again. ("/app/app/routes.py:87")

Теперь, если я сделаю тот же запрос с приложением, работающим без обратного прокси-сервера traefik, это работает. Единственное, что отличается в запросе curl, это то, что я использую http, а не https.

Вот заголовки, которые Flask получает в этом случае:

[2018-01-24 21:43:43,199] INFO - Referer: https://admin.my-app.new/
Origin: https://admin.my-app.new
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
Authority: api.my-app.new
Access-Control-Request-Headers: authorization,content-type
Host: api.my-app.new:8000
Accept: */*
Access-Control-Request-Method: GET
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate, br

[24/Jan/2018 21:43:43] "OPTIONS /api/admin/user?_end=10&_order=DESC&_sort=id&_start=0 HTTP/1.1" 200 -

Я полагаю, что что-то не так с заголовками или что-то, что сбивает с толку Flask. Я видел еще одно сообщение от 2014 года, в котором упоминалось о необходимости SERVER_NAME, но это не помогло.

Наконец, я изначально использовал NGinx в качестве резервного прокси и все заработало. Одной из вещей, с которой трудно было работать в NGinx, были перенаправления и запросы OPTION. Я все заработал после безумной погони за различными постами в блоге, но, оглядываясь назад и исправляя это, я замечаю любопытную вещь: я написал сценарий в nginx.conf, чтобы автоматически возвращать 200 для всех запросов OPTIONS!

Есть идеи, почему запросы OPTION не выполняются?

1 ответ

Решение

Как отмечает webKnjaZ: "Это ошибка".

Углубившись вглубь, я обнаружил, что проблема в том, что Flask получал другой URL для запроса GET, чем для запроса OPTIONS, и что, если CherryPy был удален, проблема исчезла. Это привело меня к этой проблеме CherryPy, которая точно описывает мою ситуацию.

https://github.com/cherrypy/cherrypy/issues/1662

Автор отметил, что ошибка появилась при переходе с CherryPy 11 на 12 (у меня был 13.x), поэтому я попытался понизить версию до 11.0.0, и это исправило ее.

Другие вопросы по тегам