由 CherryPy 托管的 Flask 应用程序:选项 returns 404

Flask app hosted by CherryPy: OPTIONS returns 404

我有一个使用 Flask 和 Flask-Restful 创建的 restful API。使用开发服务器一切正常。所有路线都在蓝图中,尽管我们在这里处理的特定路线不是 Flask-Restful 路线。这只是一个普通的 Flask 路由。

我也在用Flask-CORS。

为了部署,所有内容都已 dockerized,我使用 CherryPy 作为 WSGI 主机。因此,CherryPy 应用程序在容器中托管 Flask 应用程序。 我在另一个容器中使用 Traefik 作为反向代理。

如果我通过粘贴 URL 在 Chrome 中发出以下请求,GET 请求有效:

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

但是,如果我尝试从 React 应用程序发出相同的 GET 请求,则会发出 OPTIONS 预检请求并且失败并显示 404。 我已经在 PyCharm 中尽我所能地追踪它,问题似乎出在 Flask 的 app.py:

中的以下代码中
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(在 @app.before_request 中)收到的 headers,我会得到以下信息:

[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 反向代理的情况下使用应用程序 运行 发出相同的请求,它就可以工作。卷曲唯一不同的地方 请求是我使用的是 http,而不是 https。

这里是 Flask 在这种情况下收到的 headers:

[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 -

我认为 headers 有问题或使 Flask 感到困惑。我看到另一个 2014 年的 post 提到需要 SERVER_NAME,但这没有帮助。

最后,我最初使用 NGinx 作为备用代理,并且一切正常。其中一件事情 很难与 NGinx 一起工作的是重定向和 OPTION 请求。在疯狂地浏览各种博客后,我确实让它工作了 posts,但当我在纠正这个问题时回顾它,我注意到一件奇怪的事情:我最终在 nginx.conf 中编写了脚本 为所有 OPTIONS 请求自动 return 200!

知道 OPTION 请求失败的原因吗?

正如 webKnjaZ 所说:"It's a bug."

深入挖掘后,我发现 Flask 的 GET 请求与 OPTIONS 请求不同 URL 的问题,如果删除 CherryPy,问题就会消失。这让我想到了这个 CherryPy 问题,它准确地描述了我的情况。

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

作者注意到当从 CherryPy 11 移动到 12 时出现了错误(我在 13.x)所以我尝试降级到 11.0.0 并修复了它。