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

使用pytest发送POST请求时请求体始终为空,接口无法接收数据

Flask+pytest接口测试:请求体为空导致400 Bad Request错误

问题描述

作为pytest和测试领域新手,在测试Flask接口时遇到请求体无法传递到路由的问题:POST请求到/create/接口返回400错误(提示"the browser or proxy sent a request that this server could not understand"),打印request.form和request.get_json()均为空。已禁用CSRF防护,尝试传入csrf_token后问题依旧。

相关代码

conftest.py

@pytest.fixture()
def app():
    app = create_app()
    app.config['WTF_CSRF_ENABLED'] = False
    yield app

    # 注意:此处缩进错误,client fixture不应嵌套在app fixture内部
    @pytest.fixture()
    def client(app):
        return app.test_client()

test_project.py

def test_registration(client, app):
    headers = {"Content-Type": "application/json"}

    registerResponse = client.get("/register/")
    html = registerResponse.get_data(as_text=True)
    csrf_token = parse_form(html)

    createResponseRaw = client.post(
        "/create/",
        data={"fullName": "George Washington", "displayName": "gwashington", "csrf_token": csrf_token},
        headers={"Content-Type": "application/json"}
    )
    createResponse = return_response(createResponseRaw)
    print(createResponse)

路由代码

@appBP.route('/create/', methods=['POST'])
def create():
    msg = {"results": ""}
    print(request.method)  # 输出POST
    print(request.form)    # 输出ImmutableMultiDict([])
    print(request.headers.get('Content-Type'))  # 输出application/json
    data = request.get_json()

问题分析

  1. 请求数据格式不匹配:设置了Content-Type: application/json,但用data参数传递字典,Flask的test_client.post会将data参数的字典默认编码为表单格式(application/x-www-form-urlencoded),而非JSON字符串,导致服务器无法解析请求体。
  2. fixture缩进错误:client fixture嵌套在app fixture内部,pytest无法识别为独立的测试夹具,可能导致测试客户端初始化异常。
  3. 多余的csrf_token:已禁用CSRF,无需传入该参数,属于冗余操作。

解决方案

1. 修正fixture缩进

将client fixture与app fixture平级,确保pytest能正确加载:

@pytest.fixture()
def app():
    app = create_app()
    app.config['WTF_CSRF_ENABLED'] = False
    yield app

@pytest.fixture()
def client(app):
    return app.test_client()

2. 正确传递JSON请求体

使用test_client.post的json参数直接传递字典,该参数会自动将字典序列化为JSON字符串,并设置正确的Content-Type: application/json头:

def test_registration(client, app):
    # 无需手动设置Content-Type,也不需要csrf_token
    createResponseRaw = client.post(
        "/create/",
        json={"fullName": "George Washington", "displayName": "gwashington"}
    )
    createResponse = return_response(createResponseRaw)
    print(createResponse)

备选方案:手动序列化JSON

如果需要手动控制请求头,可使用json.dumps将字典转为JSON字符串后通过data参数传递:

import json

def test_registration(client, app):
    headers = {"Content-Type": "application/json"}
    payload = json.dumps({"fullName": "George Washington", "displayName": "gwashington"})
    
    createResponseRaw = client.post(
        "/create/",
        data=payload,
        headers=headers
    )
    createResponse = return_response(createResponseRaw)
    print(createResponse)

3. 路由验证

修改路由代码,确保正确获取JSON数据:

@appBP.route('/create/', methods=['POST'])
def create():
    msg = {"results": ""}
    data = request.get_json()
    if not data:
        return jsonify({"error": "Invalid JSON data"}), 400
    # 处理业务逻辑
    msg["results"] = "Success"
    return jsonify(msg)

内容的提问来源于stack exchange,提问作者newdeveloper

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 14:05:13