You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用ngrok暴露本地Flask后端时,Axios跨域请求因CORS凭证兼容问题报错的求助

使用ngrok暴露本地Flask后端时,Axios跨域请求因CORS凭证兼容问题报错的求助

问题描述

我最近碰到一个跨域请求的棘手问题,想请大家帮忙看看:

  • 我的Flask后端跑在http://localhost:5000,React前端部署在http://localhost:3000,直接用本地后端地址的时候,所有请求都能正常工作。
  • 因为需要从其他网络访问本地后端,我用ngrok生成了一个公网地址(比如https://453c-162-199-93-254.ngrok-free.app),但用这个地址通过Axios发起请求时,浏览器直接抛出了CORS错误:

Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at ‘https://453c-162-199-93-254.ngrok-free.app/@me’. (Reason: Credential is not supported if the CORS header ‘Access-Control-Allow-Origin’ is ‘*’)

另外,用ngrok地址访问时还会返回user: Unauthorized,哪怕绕开了ngrok的浏览器警告,登录后的GET /@me请求依然无法正常获取数据。

已尝试的解决方案

我已经试了好几种方法,但都没能彻底解决问题:

  • 放弃自定义的axios实例(之前用axios.create创建了httpClient),直接用axios.get发起请求
  • 在创建axios实例前设置全局的axios.defaults.withCredentials = true,也在单个请求里单独加了withCredentials: true选项:
    const resp = await axios.get(`${backendLink}/@me`, { withCredentials: true });
    
  • 在Flask里配置CORS时指定origins:CORS(app, origins=["http://localhost:3000"]),也试过给接口单独加@cross_origin(origins=[...])装饰器
  • 在React的package.json里配置了代理:"proxy": "https://fe10-162-199-93-254.ngrok-free.app"
  • 给Flask的session配置了SameSite和Secure属性:
    app.config["SESSION_COOKIE_SAMESITE"] = "None"
    app.config["SESSION_COOKIE_SECURE"] = True
    

最终解决方法

后来我调整了Flask的CORS配置,把ngrok的公网地址也加入到origins列表里,同时开启supports_credentials=True,问题居然就解决了!具体配置代码如下:

CORS(app, supports_credentials=True, origins=[
    "http://localhost:3000",
    "http://thecasecomp.com",  # 我的线上域名,大家根据自己的实际情况替换
    "https://453c-162-199-93-254.ngrok-free.app"  # ngrok生成的公网地址
])

现在想明白了,当请求携带凭证(比如session cookie)时,浏览器是不允许Access-Control-Allow-Origin设为通配符*的,必须把前端所在的所有域名(包括本地开发地址和ngrok公网地址)都明确加入到CORS的origins中才行。

我的Flask后端核心代码

给大家贴一下我的app.py核心部分,方便参考:

from flask import Flask, request, abort, jsonify, session
from flask_bcrypt import Bcrypt
from flask_session import Session
from flask_cors import CORS, cross_origin
from config import ApplicationConfig
from models import db, User

app = Flask(__name__)
app.config.from_object(ApplicationConfig)
bcrypt = Bcrypt(app)

# 关键的CORS配置
CORS(app, supports_credentials=True, origins=[
    "http://localhost:3000",
    "http://localhost:5000",
    "https://453c-162-199-93-254.ngrok-free.app",
])

server_session = Session(app)
db.init_app(app)

with app.app_context():
    db.create_all()

# 获取当前登录用户接口
@app.route("/@me")
def get_current_user():
    user_id = session.get("user_id")
    if not user_id:
        return jsonify({"error": "User unauthorized."}), 401
    user = User.query.filter_by(id = user_id).first()
    if user is None:
        return jsonify({"error": "User not found."}), 404
    return jsonify({
        "id": user.id,
        "email": user.email,
        "first_name": user.first_name,
        "last_name": user.last_name,
        "phone_number": user.phone_number,
        "grade": user.grade,
        "school": user.school
    })

# 注册接口(省略部分代码)
@app.route("/registration", methods=["POST"])
def register_user():
    email = request.json["email"]
    password = request.json["password"]
    first_name = request.json["firstName"]
    last_name = request.json["lastName"]
    phone_number = request.json["phone"]
    grade = request.json["grade"]
    school = request.json["school"]
    
    user_exists = User.query.filter_by(email = email).first() is not None
    if user_exists:
        return jsonify({"error": "User already exists."}), 409
    
    hashed_password = bcrypt.generate_password_hash(password)
    new_user = User(email = email, password = hashed_password, first_name = first_name, last_name = last_name, phone_number = phone_number, grade = grade, school = school)
    db.session.add(new_user)
    db.session.commit()
    
    session["user_id"] = new_user.id
    return jsonify({
        "id": new_user.id,
        "email": new_user.email,
        "first_name": new_user.first_name,
        "last_name": new_user.last_name,
        "phone_number": new_user.phone_number,
        "grade": new_user.grade,
        "school": new_user.school
    })

# 删除用户接口(省略部分代码)
@app.route("/remove-user", methods=["POST"])
def remove_user():
    user_id = request.json["user_id"]
    if not user_id:
        return jsonify({"error": "User ID not found."}), 404
    user = User.query.filter_by(id=user_id).first()
    if user:
        db.session.delete(user)
        db.session.commit()
        return jsonify({"message": "User removed successfully."}), 200

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 09:50:30