8

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

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

以下是正在开发中的相关代码:

# 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 missingCORS 错误)。

现在我想知道该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;
    }
}
4

3 回答 3

4

问题是,您从中请求资源的服务器应该具有 CORS 标头(让它成为serverA),而不是需要远程文件的服务器(serverB)。如果serverANGINX,或者Apache2您可以使用它来将 CORS 标头添加到响应中:

NGINX

add_header Access-Control-Allow-Origin *;
# or
add_header Access-Control-Allow-Origin serverB;

阿帕奇2

Header set Access-Control-Allow-Origin "*"
# or
Header set Access-Control-Allow-Origin "serverB"

上面的意思是“允许 * 或 serverB 从此服务器 (serverA) 获取资源”

对于刚接触 CORS 的任何人,我推荐来自 Mozilla 的这两篇(12)简短读物。我认为他们很擅长解释基础知识。

于 2021-01-14T06:19:04.197 回答
2

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


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, DELETE, DNT, DPR, Date, Default-Style, Delta-Base, Depth, Derived-From, Destination, Differential-ID, Digest, ETag, Expect, Expires, Ext, From, GET, GetProfile, HEAD, 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, OPTIONS, OWS, Opt, Optional, Ordering-Type, Origin, Overwrite, P3P, PEP, PICS-Label, POST, PUT, 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, TRACE, 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, 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, DELETE, DNT, DPR, Date, Default-Style, Delta-Base, Depth, Derived-From, Destination, Differential-ID, Digest, ETag, Expect, Expires, Ext, From, GET, GetProfile, HEAD, 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, OPTIONS, OWS, Opt, Optional, Ordering-Type, Origin, Overwrite, P3P, PEP, PICS-Label, POST, PUT, 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, TRACE, 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';


    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, POST, OPTIONS, PUT, DELETE, HEAD';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Origin,Content-Type,Accept,Authorization,Access-Control-Expose-Headers,Access-Control-Allow-Origin,Access-Control-Allow-Methods,Access-Control-Expose-Headers';
add_header 'Access-Control-Expose-Headers' 'Origin,Content-Type,Accept,Authorization,Access-Control-Expose-Headers,Access-Control-Allow-Origin,Access-Control-Allow-Methods,Access-Control-Expose-Headers'

您还可以查看此链接以获取有关 CORS 的更多详细信息。关联

于 2021-01-14T13:47:54.047 回答
2

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

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

于 2021-01-20T21:24:55.473 回答