React fetch调用Flask POST接口返回400错误问题排查
问题现象
使用Python Flask开发了包含GET、POST方法的REST API,前端通过React JS的fetch()方法发起接口调用:
- GET接口调用逻辑正常,在Postman工具、浏览器控制台均可正常获取返回数据
- POST接口在Postman中可正常调用,但浏览器环境下调用时返回400状态码,报错信息如下:
POST http://127.0.0.1:5000/fc/FC001 net::ERR_ABORTED 400 (BAD REQUEST))
相关代码
前端React JS调用代码
const postFcByRequestNumber = async (RequestNumber, url, name, city) => { const apiUrl = "http://127.0.0.1:5000/fc/" + RequestNumber; await fetch(apiUrl, { method: "POST", mode: "no-cors", body: JSON.stringify({ "url": url, "name": name, "city": city, }), headers: { "Content-Type": "application/json; charset=UTF-8" /* Tried below changes, but nothing worked */ // "Content-Type": "application/json" //"Accept": "application/json", // "Accept-Encoding": "gzip, deflate, br", }, }) .then((response) => response.json()) .then((data) => { console.log("Response for postFcByRequestNumber {FC001} is :", data); }) .catch((err) => { console.log(err.message); }); };
后端Flask运行代码
@app.post("/fc/<requestNumber>") #@app.route("/fc/<requestNumber>", methods=["POST"]) def post_fc_by_requestNumber(requestNumber): if (not request.view_args['requestNumber']): return "Please send requestNumber.", 401 if request.is_json: newRequest = request.get_json() newRequest["id"] = _find_next_request_id() newRequest["requestNumber"] = request.view_args['requestNumber'] existingRequests.append(newRequest) response = jsonify(newRequest) # Enable Access-Control-Allow-Origin response.headers.add("Access-Control-Allow-Origin", "*") return response, 201 return {"error": "Bad Request : Request must be JSON."}, 400
已尝试的排查操作
以下操作均未解决问题,接口仍返回400/404错误状态码:
- 删除Flask代码末尾的400错误返回语句,避免显式返回404错误
- 同时移除前后端代码URL中的path参数
requestNumber - 删除Python代码中响应头的CORS相关配置
异常现象
排查过程中发现:浏览器控制台显示请求头的Content-Type为text/plain;charset=UTF-8,与Postman正常调用时的application/json类型不符;即使手动在fetch请求的headers中配置"Content-Type": "application/json; charset=UTF-8",该配置也未生效,浏览器抓取的实际请求头如下:
Request Headers : Accept: application/json Accept-Encoding: gzip, deflate, br Accept-Language: en-GB,en-US;q=0.9,en;q=0.8 Connection: keep-alive Content-Length: 58 **Content-Type: text/plain;charset=UTF-8** Host: 127.0.0.1:5000 Origin: http://localhost:3000 Referer: http://localhost:3000/ sec-ch-ua: ".Not/A)Brand";v="99", "Google Chrome";v="103", "Chromium";v="103" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "macOS" Sec-Fetch-Dest: empty Sec-Fetch-Mode: no-cors Sec-Fetch-Site: cross-site
问题根因
核心触发原因是前端fetch请求错误配置了mode: "no-cors":
- 浏览器对
no-cors模式的跨域请求有强制限制,仅允许发送CORS安全列表内的请求头,Content-Type: application/json不属于安全头范围,会被浏览器自动覆盖为text/plain类型,这就是手动配置Content-Type不生效的原因 - 后端Flask接口通过
request.is_json判断请求格式时,因为收到的Content-Type是text/plain,直接判定请求不是合法JSON,触发末尾的400错误返回逻辑 - 即使后端正常返回响应,
no-cors模式下前端也只能拿到不透明的opaque响应,无法正常解析JSON内容,后续逻辑还是会报错
解决方案
- 移除前端fetch配置中的
mode: "no-cors"项,使用默认的cors模式发起跨域请求 - 后端使用标准CORS配置替代手动零散加响应头的方式,安装flask-cors扩展统一处理跨域:
- 安装依赖:
pip install flask-cors- 在Flask初始化代码中加入全局CORS配置(开发环境可直接放开所有源,生产环境按需配置允许的域名、请求方法、请求头即可):
from flask import Flask from flask_cors import CORS app = Flask(__name__) CORS(app) - 配置完成后重启Flask服务,浏览器发起请求时会正常携带
Content-Type: application/json头,后端JSON校验通过即可正常处理请求,前端也能正常解析返回的JSON响应。
内容的提问来源于stack exchange,提问作者Tanuj Kathuria
相关产品推荐
相关产品推荐

