使用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()
问题分析
- 请求数据格式不匹配:设置了
Content-Type: application/json,但用data参数传递字典,Flask的test_client.post会将data参数的字典默认编码为表单格式(application/x-www-form-urlencoded),而非JSON字符串,导致服务器无法解析请求体。 - fixture缩进错误:
clientfixture嵌套在appfixture内部,pytest无法识别为独立的测试夹具,可能导致测试客户端初始化异常。 - 多余的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
相关产品推荐
相关产品推荐

