为什么 Flask-Cors 在生产中没有检测到我的跨域域?

问题描述

我的网站有一个独立的前端和后端服务器,所以我的后端服务器需要开放CORS权限,以便前端可以向其请求数据。

我在开发中使用了 Flask-Cors 成功,但是当我部署到生产时它不起作用。 (请注意,我已经查看了关于 SO 的其他flask-cors 问题,但没有一个适合我的情况)

这是在开发中工作的相关代码

# 3rd party imports
import flask
from flask import Flask,request,redirect,send_from_directory,jsonify
from flask_cors import CORS

# Create the app
app = Flask(__name__)
CORS(app,origins=[
  'http://localhost:5001',])

# Define the routes
@app.route('/')
def index():
  # no CORS code was necessary here
  app.logger.info(f'request is: {flask.request}')

我尝试过的:

  • 将我服务器的 IP 地址 'http://162.243.168.182:5001' 添加到 CORS 列表还不足以解决问题,尽管我知道它应该存在。
  • 似乎使用 '*' 允许所有来源也不起作用。 (非常可疑!)

请注意,我使用的是 Docker 容器,因此我在开发和生产之间的环境几乎相同。但不同的是我在不同的服务器上,我修改了前端以将请求发送到新的 IP 地址(导致著名的 “Access-Control-Allow-Origin” header missing CORS 错误)。

现在我想知道 flask.request 对象是否以某种方式丢失了信息,这会导致 Flask-Cors 没有像预期的那样发送 Access-Control-Allow-Origin 标头。如果您认为有帮助,我可以提供该日志信息!

更多信息!

我在 PROD 中使用的 Dockerfile 是:

# base image
FROM tianGolo/uwsgi-Nginx-flask:python3.8-2020-12-19

# install deps
RUN pip3 install ediblepickle==1.1.3
# RUN pip3 install flask==1.1.2 # pre-installed on tianGolo/uwsgi-Nginx-flask
RUN pip3 install flask-cors==3.0.9
RUN pip3 install numpy==1.19.2
RUN pip3 install scipy==1.5.2
RUN pip3 install pandas==1.1.2
RUN pip3 install networkx==2.5

# pull in files for deployment
copY ./app /app

# Note that there is no CMD to run because the CMD set in the base image is what we already wanted.  As long as the Flask app is called `app`,the python file is named `main.py`,the parent directory is named `app`,and that same directory gets copied into `/app`,then the base image is designed to make our app work out-of-the-Box.

我用来启动它的命令是:

docker build -t mvlancellotti/tennis-backend:prod -f prod.Dockerfile . && docker run --rm -p 5000:80 --name tennis-backend-container mvlancellotti/tennis-backend:prod

进入容器的/app目录,有一个包含内容文件uwsgi.ini

[uwsgi]
module = main
callable = app

这似乎有效,文件 /etc/Nginx/Nginx.conf内容

user  Nginx;
worker_processes 1;
error_log  /var/log/Nginx/error.log warn;
pid        /var/run/Nginx.pid;
events {
    worker_connections 1024;
}
http {
    include       /etc/Nginx/mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  /var/log/Nginx/access.log  main;
    sendfile        on;
    keepalive_timeout  65;
    include /etc/Nginx/conf.d/*.conf;
}
daemon off;

并且文件 /etc/Nginx/conf.d/Nginx.conf内容

server {
    listen 80;
    location / {
        try_files $uri @app;
    }
    location @app {
        include uwsgi_params;
        uwsgi_pass unix:///tmp/uwsgi.sock;
    }
    location /static {
        alias /app/static;
    }
}

解决方法

如果你在实际应用之前使用 NGINX 或 Apache2 作为代理,你也可以配置它来为你处理 CORS 标头。

NGINX

add_header Access-Control-Allow-Origin *;

Apache2

Header set Access-Control-Allow-Origin "*"

将它放在生成初始响应的地方,它将允许从任何来源加载资源。在 prod 中,您可能应该将 * 替换为您要使用的来源。如果原点不会经常或动态更改 - 您可能不需要 Flask CORS。

否则,您需要做的第一件事是在浏览器中打开开发者控制台并检查您对网站的初始请求的响应标头。这是定义来源和 CORS 策略的地方。应该有一个响应标头 Access-Control-Allow-Origin,它定义了允许浏览器从何处加载其他资源。如果没有标题,则不允许有额外的来源。如果标头在那里并且您仍然收到错误,那么您尝试加载的资源来源与规则不匹配。在这种情况下检查拼写错误。

对于 CORS 的新手,我推荐这两个 (1,2) 来自 Mozilla 的简短读物。我认为他们在解释基础知识方面做得很好。

,

我想添加评论,但仍然没有足够的代表..

Nginx add_header 不适用于错误代码。

此外,当您收到任何类型的错误(400、500、502 等)时,标题也会丢失。浏览器会向您显示 CORS,但没关系,其他地方出了问题。 因为这个而失去很多时间是很常见的......

我访问了你的应用(抱歉,如果没有提到这样做)。它加载并且一些过滤器选项导致 502 并且浏览器会说:哦,CORS! 但看起来有些东西正在消亡并回来了。

有关 add_header 和错误的信息:https://serverfault.com/questions/431274/nginx-services-fails-for-cross-domain-requests-if-the-service-returns-error

,

请注意,您需要在生产环境中考虑几件事。 首先,请分享您与 docker 相关的配置(Dockerfile、Docker-Compose 如果您有),因为您正在尝试解决与根本原因无关的问题。例如,如果您使用 ApacheNginx 作为 reverse_proxy 来处理 HTTP 请求,那么您需要将相关标头添加到它们的配置中。但是我建议您使用以下代码,以前我遇到过像您一样的问题,以下代码解决了我的问题:


cors = CORS(flask_app,resources={r"/api/*": {"origins": "*","allow_headers": "*","expose_headers": "*"}})

更新:添加 Nginx 配置

这是 Nginx 最完整和最开放的 CORS 配置:

Nginx 配置完成 CORS 开放

对于某些配置,某些旧浏览器不支持通配符(* 符号),因此,我以某种方式添加了所有可能值的列表,但您需要根据您的应用程序要求和策略对其进行修改。此外,您可以将“add_headers”部分移动到配置文件中需要存在的任何位置。

server {
    listen 80;

    
    add_header 'Access-Control-Allow-Origin' '*';
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Methods' 'CONNECT,DEBUG,DELETE,DONE,GET,HEAD,HTTP,HTTP/0.9,HTTP/1.0,HTTP/1.1,HTTP/2,OPTIONS,ORIGIN,ORIGINS,PATCH,POST,PUT,QUIC,REST,SESSION,SHOULD,SPDY,TRACE,TRACK';
    add_header 'Access-Control-Allow-Headers' 'Accept,Accept-CH,Accept-Charset,Accept-Datetime,Accept-Encoding,Accept-Ext,Accept-Features,Accept-Language,Accept-Params,Accept-Ranges,Access-Control-Allow-Credentials,Access-Control-Allow-Headers,Access-Control-Allow-Methods,Access-Control-Allow-Origin,Access-Control-Expose-Headers,Access-Control-Max-Age,Access-Control-Request-Headers,Access-Control-Request-Method,Age,Allow,Alternates,Authentication-Info,Authorization,C-Ext,C-Man,C-Opt,C-PEP,C-PEP-Info,CONNECT,Cache-Control,Compliance,Connection,Content-Base,Content-Disposition,Content-Encoding,Content-ID,Content-Language,Content-Length,Content-Location,Content-MD5,Content-Range,Content-Script-Type,Content-Security-Policy,Content-Style-Type,Content-Transfer-Encoding,Content-Type,Content-Version,Cookie,Cost,DAV,DNT,DPR,Date,Default-Style,Delta-Base,Depth,Derived-From,Destination,Differential-ID,Digest,ETag,Expect,Expires,Ext,From,GetProfile,HTTP-date,Host,IM,If,If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,Keep-Alive,Label,Last-Event-ID,Last-Modified,Link,Location,Lock-Token,MIME-Version,Man,Max-Forwards,Media-Range,Message-ID,Meter,Negotiate,Non-Compliance,OPTION,OWS,Opt,Optional,Ordering-Type,Origin,Overwrite,P3P,PEP,PICS-Label,Pep-Info,Permanent,Position,Pragma,ProfileObject,Protocol,Protocol-Query,Protocol-Request,Proxy-Authenticate,Proxy-Authentication-Info,Proxy-Authorization,Proxy-Features,Proxy-Instruction,Public,RWS,Range,Referer,Refresh,Resolution-Hint,Resolver-Location,Retry-After,Safe,Sec-Websocket-Extensions,Sec-Websocket-Key,Sec-Websocket-Origin,Sec-Websocket-Protocol,Sec-Websocket-Version,Security-Scheme,Server,Set-Cookie,Set-Cookie2,SetProfile,SoapAction,Status,Status-URI,Strict-Transport-Security,SubOK,Subst,Surrogate-Capability,Surrogate-Control,TCN,TE,Timeout,Title,Trailer,Transfer-Encoding,UA-Color,UA-Media,UA-Pixels,UA-Resolution,UA-Windowpixels,URI,Upgrade,User-Agent,Variant-Vary,Vary,Version,Via,Viewport-Width,WWW-Authenticate,Want-Digest,Warning,Width,X-Content-Duration,X-Content-Security-Policy,X-Content-Type-Options,X-CustomHeader,X-DNSPrefetch-Control,X-Forwarded-For,X-Forwarded-Port,X-Forwarded-Proto,X-Frame-Options,X-Modified,X-OTHER,X-PING,X-PINGOTHER,X-Powered-By,X-Requested-With';
    add_header 'Access-Control-Expose-Headers' 'Accept,X-Requested-With';


    location / {
        try_files $uri @app;
    }
    location @app {
        include uwsgi_params;
        uwsgi_pass unix:///tmp/uwsgi.sock;
    }
    location /static {
        alias /app/static;
    }
}

Nginx 更简单的 CORS 配置文件

此外,您可以使用以下代码,但也许您会遇到一些 cors 错误,您可以通过与之前的示例进行比较来快速解决这些错误。大多数情况下,响应中有一些标题不被允许暴露在列表中。

add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET,HEAD';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Origin,Accept,Access-Control-Expose-Headers';
add_header 'Access-Control-Expose-Headers' 'Origin,Access-Control-Expose-Headers'

您还可以查看此链接以了解有关 CORS 的更多详细信息。 Link

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...