使用 Flask 遇到 CORS 问题

Posted

技术标签:

【中文标题】使用 Flask 遇到 CORS 问题【英文标题】:Running into issues with CORS with Flask 【发布时间】:2021-04-06 17:58:31 【问题描述】:

我已经搜索了好几个小时,试图找到解决问题的好方法,但我似乎找不到解决方案。基本上,我使用蓝图将我的 Flask API 分解为两个单独的文件,一个用作主要的 Flask 应用程序,另一个用于处理所有身份验证路由。我遇到了 CORS 问题......在我将它们分开之前,它与 flask-cors 库一起工作得很好。但是,当我使用蓝图将其分解为单独的文件时,它不起作用。我做了很多研究,似乎有几种方法可以做到,但最好的方法似乎是解决服务器端的问题(至少在理论上,因为我还没有找到解决方案)。

app.py

    # Third-party libraries
    from flask import Flask
    from flask_cors import CORS
    
    # Internal imports
    from login import login_page

    # Flask app setup
    app = Flask(__name__)
    
    app.register_blueprint(login_page)
    CORS(app)
    app.config['CORS_HEADERS'] = 'Content-Type'
    if __name__ == "__main__":
          app.run(host="localhost", debug=True)

login.py

# Third-party libraries
from flask import Flask, redirect, request, url_for, Blueprint, render_template, abort
from flask_login import (
    LoginManager,
    current_user,
    login_required,
    login_user,
    logout_user
)
from oauthlib.oauth2 import WebApplicationClient
import requests
from flask_cors import CORS

login_page = Blueprint('login_page', __name__)
CORS(login_page)

# Login route
@login_page.route('/login', methods=['GET'])
def login():
    # Find out what URL to hit for Google login
    google_provider_config = get_google_provider_config()
    authorization_endpoint = google_provider_config["authorization_endpoint"]
    # Use library to construct the request for Google login and provide
    # scopes that let you retrieve user's profile from Google
    request_uri = client.prepare_request_uri(
        authorization_endpoint,
        redirect_uri = request.base_url + "/callback",
        scope = ["openid", "email", "profile"]
    )
    return redirect(request_uri)

来自文档: https://flask-cors.readthedocs.io/en/latest/api.html#using-cors-with-blueprints

这似乎是我正在做的......但它不起作用。

编辑: 反应代码:

authenticate = async () => 
    console.log('authenticate called')
    const response = await users.get('/login');

我添加了一条测试路线,以查看我处理蓝图的方式是否与 flask-cors 库不正确,如下所示:

@login_page.route('/test')
def test():
    print('test')
    return 'test'

果然,我能够在控制台上看到文本打印。所以这让我相信是其他原因阻止我访问 Google 的身份验证服务器。

Flask 应用程序在 localhost:5000 上运行,而 React 应用程序在 localhost:3000 上运行。在login 中传入redirect 方法的字符串如下:

https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=None&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2Flogin%2Fcallback&scope=openid+email+profile

但是,这在使用 React 之前有效。

Chrome 控制台错误:

从源“http://localhost:3000”访问“...”处的 XMLHttpRequest(从“http://localhost:3000/login”重定向)已被 CORS 策略阻止:没有“访问控制” -Allow-Origin' 标头存在于请求的资源上。

我还在我的 package.json 文件中添加了一个代理,如下所示:

  "proxy": "http://localhost:5000"

我来自:https://blog.miguelgrinberg.com/post/how-to-create-a-react--flask-project/page/3

更新:

我决定采用使用 nginx 解决此问题的方法,因为该 flask-cors 库似乎不适合此问题,因为似乎没有解决方案。

Nginx.conf

    user www-data;
    worker_processes 1;
    pid /run/nginx.pid;
    include /etc/nginx/modules-enabled/*.conf;
    
    events 
        worker_connections 1024;
    
    
http   

    upstream react-client 
        server react-client;
    

    upstream flask-backend 
        server flask-backend;
    

    server 
        listen 80;
        server_name localhost;

        location / 
            # From docker-compose, react-client port 80 is exposed
            proxy_pass          http://react-client;
        

        # location /login/callback

        # location /logout
    

    server 
        listen 3000;
        server_name localhost;

        location /login 
            proxy_pass          http://flask-backend;
        
    

docker-compose.yml:

version: '3'

services:

  reverse-proxy:
    image: nginx:1.17.10
    container_name: reverse-proxy
    depends_on: 
      - flask-backend
      - react-client
    volumes:
      - ./reverse-proxy/nginx.conf:/etc/nginx/nginx.conf
    ports:
      - 80:80
  
  react-client:
    image: react-client
    container_name: react-client
    build:
      context: ./client
    depends_on: 
      - flask-backend
    ports:
      - 3000:3000
    restart: on-failure
  
  flask-backend:
    image: flask-backend
    container_name: flask-backend
    build:
      context: ./api
    ports:
      - 5000:5000
    restart: on-failure

使用 Nginx 配置和 Docker 文件,我可以转到 http://localhost:80,它将我转发到 react 客户端。这一次,我没有收到 CORS 错误,但我确实在我的检查员中收到了这条消息,Failed to load resource: The network connection was lost.

我的理解是这样的:

http://localhost:80 -> http://localhost:3000,那么当一个按钮被按下时,它会提示新的路线

http://localhost:3000/login -> http://localhost:5000/login

我有两个服务器块,因为 Web 应用程序在 3000 端口上运行,而 Nginx 服务器在 80 端口上运行。

【问题讨论】:

看看这个帖子***.com/questions/26980713/…它可能对你有帮助 @cizario 我已经试过了.. :( 你以前遇到过这个问题吗? 您是否尝试过使用 cors 库而不仅仅是您的蓝图来初始化您的应用程序,您是否有特定的原因来初始化蓝图? @Craicerjack 是的,我做到了.. 我仍然遇到同样的问题。 :( 【参考方案1】:

代替CORS(login_page) 试试CORS(login_page, resources=r'/login')

编辑:解释为什么这可能有效。

您收到的错误表明 /login 路由不允许 CORS。您正在正确地实例化 Flask-CORS,所以我怀疑如果您尝试描述您希望 CORS 应用于您的特定路线将解决问题。

文档使CORS(login_page) 看起来应该自动打开到 CORS 的所有路由,但因为这不起作用,尝试上述答案可能会提供更好的结果。

【讨论】:

在 *** 上回答问题时,请说明为什么您的答案是正确的。

以上是关于使用 Flask 遇到 CORS 问题的主要内容,如果未能解决你的问题,请参考以下文章

flask 跨域问题

使用 Flask 和 React 的 localhost CORS 错误

Python Flask Cors 问题

在 Flask 中允许 CORS

来自 React 的 Flask API 调用的 CORS 问题都在 localhost

由于不允许的预检标头,Vue.js 前端与 Flask 后端 CORS 问题交互