Flask本地前后端POST请求触发CORS错误,寻求解决方案
问题情况
本地前端(localhost:5173)向Flask后端(localhost:5000)发送请求时,GET路由可正常运行,但POST请求持续触发CORS错误,错误核心提示为预请求的响应包含重定向,不符合CORS规则。
相关代码
后端配置代码
import os from flask import Flask from flask_cors import CORS from app.extensions import db, migrate, api from app.controller.livro_controller import api as livro_ns class testConfig(): DEBUG = True SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(os.path.abspath(os.path.dirname(__file__)), 'flask_boilerplate_main.db') SQLALCHEMY_TRACK_MODIFICATIONS = False def create_app(): app = Flask(__name__) app.config.from_object(testConfig) CORS(app) db.init_app(app) migrate.init_app(app, db) api.init_app(app) api.add_namespace(livro_ns, path="/livro") return app
livro_controller.py代码
from flask import request, make_response from flask_restx import Resource, marshal from flask_cors import CORS, cross_origin from app.util.dto import LivroDto from app.service.livro_service import ( editar_livro, excluir_livro, listar_todas_livros, criar_livro, ) api = LivroDto.api _livro = LivroDto.livro @api.route("/") class Livro(Resource): @api.doc('list_of_registered_users') @api.response(201, 'User successfully created.') @api.expect(_livro, validate=True) def post(self): data = request.json try: response = criar_livro(data) return response, 201 except Exception as e: return {"message": str(e)}, 500 @api.marshal_list_with(_livro, envelope="data") def get(self): try: return listar_todas_livros(), 200 except Exception as e: return {"message": str(e)}, 500 @api.route("/<int:id_livro>") @api.param("id_livro", "Book ID") class LivroComId(Resource): @api.expect(_livro, validate=True) def put(self, id_livro): data = request.json try: response = editar_livro(id_livro, data) return response, 200 except Exception as e: return {"message": "An error occurred while updating the book."}, 500 def delete(self, id_livro): try: response = excluir_livro(id_livro) return response, 204 except Exception as e: return {"message": "An error occurred while deleting the book."}, 500
前端请求代码
import axios from "axios"; import { livroType } from "../types/livro"; export function criarLivro(livro: livroType) { return axios.post("http://localhost:5000/livro", livro); } export function todosLivros() { return axios.get("http://localhost:5000/livro"); }
错误信息
Access to XMLHttpRequest at 'http://localhost:5000/livro' from origin 'http://localhost:5173' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
POST http://localhost:5000/livro net::ERR_FAILED
xhr.js:158 Uncaught (in promise) AxiosError {message: 'Network Error', name: 'AxiosError', code: 'ERR_NETWORK', config: {…}, request: XMLHttpRequest, …}
apiFunctions.ts:6 XHR failed loading: POST "http://localhost:5000/livro".
解决方案
1. 解决路由重定向问题
错误核心是预请求被重定向,这是Flask默认strict_slashes行为导致的:当请求路径末尾无斜杠,而路由定义带斜杠时,Flask会自动重定向到带斜杠的路径,但CORS预请求(OPTIONS)不允许重定向。
修改Flask初始化代码,关闭严格斜杠检查:
def create_app(): # 添加 strict_slashes=False 关闭自动重定向 app = Flask(__name__, strict_slashes=False) app.config.from_object(testConfig) CORS(app) # ... 其余代码不变
或者统一前后端路径:前端请求改为http://localhost:5000/livro/(带末尾斜杠),与后端@api.route("/")的定义匹配。
2. 优化CORS配置
全局CORS配置可以更明确,指定允许的源和支持凭据,避免覆盖问题:
def create_app(): app = Flask(__name__, strict_slashes=False) app.config.from_object(testConfig) # 明确指定允许的前端源,支持OPTIONS方法和凭据 CORS(app, origins="http://localhost:5173", supports_credentials=True) # ... 其余代码不变
也可以针对命名空间单独配置CORS,在livro_controller.py的类上添加装饰器:
@api.route("/") @cross_origin(origins="http://localhost:5173") class Livro(Resource): # ... 类内代码不变
3. 手动处理预请求
确保Flask-CORS正确处理OPTIONS请求,可在Livro类中手动添加OPTIONS方法支持:
@api.route("/") class Livro(Resource): def options(self): # 直接返回200,让预请求通过 return {'Allow': 'GET, POST, OPTIONS'}, 200 # ... 其余post、get方法不变
验证步骤
- 重启Flask后端服务
- 重新发送POST请求,检查是否仍有CORS错误
- 若仍有问题,打开浏览器开发者工具的网络标签,查看OPTIONS请求的响应头,确认是否包含
Access-Control-Allow-Origin等CORS相关头
内容的提问来源于stack exchange,提问作者Lucas Diniz

