FastAPI+Ariadne GraphQL服务中,httpx发送Mutation请求返回400错误的正确请求方式咨询
FastAPI+Ariadne GraphQL服务中,httpx发送Mutation请求返回400错误的正确请求方式咨询
看起来你遇到的问题挺典型的——明明在Playground和curl里都能正常调用的Mutation,换成httpx的POST请求就返回400错误,而且GET请求的Query还能正常工作。我帮你梳理几个可能的解决方向,你可以逐个试试:
1. 确保请求体包含operationName字段
虽然GraphQL规范里operationName不是强制要求,但部分服务端实现(包括Ariadne的某些场景)会在query中明确命名操作时要求这个字段。你在curl里可能隐式包含了它,而httpx请求里漏掉了。修改你的请求代码,添加这个字段试试:
import httpx query = """ mutation CleanText($context: ExecutionContextInput!, $state: CleanTextInput!) { cleanText(context: $context, state: $state) { response { text } } } """ variables = { "context": {"executionId": "123"}, "state": {"text": "Hello World!!"} } # 添加operationName字段,和你的mutation名称一致 payload = { "query": query, "variables": variables, "operationName": "CleanText" } resp = httpx.post( "http://localhost:8000/graphql", json=payload ) print(resp.status_code) print(resp.text)
2. 对比httpx和curl的请求体差异
既然curl能正常工作,你可以先把httpx要发送的请求体打印出来,和curl的请求体做精确对比,看看有没有序列化差异或者格式问题:
import json import httpx query = """ mutation CleanText($context: ExecutionContextInput!, $state: CleanTextInput!) { cleanText(context: $context, state: $state) { response { text } } } """ variables = { "context": {"executionId": "123"}, "state": {"text": "Hello World!!"} } payload = {"query": query, "variables": variables, "operationName": "CleanText"} # 打印序列化后的请求体,和curl里的内容对比 print(json.dumps(payload, indent=2)) resp = httpx.post( "http://localhost:8000/graphql", json=payload )
如果发现差异,比如字符串转义、换行符处理等问题,可以手动构造请求体字符串,用content参数发送,模拟curl的行为:
resp = httpx.post( "http://localhost:8000/graphql", content=json.dumps(payload), headers={"Content-Type": "application/json"} )
3. 升级httpx到最新版本
旧版本的httpx可能在JSON序列化或者请求头处理上存在bug,尝试升级到最新版本:
pip install --upgrade httpx
4. 检查服务端的请求日志
如果上面的方法都没用,你可以在FastAPI服务端添加请求日志,看看收到的httpx请求到底是什么样的,对比curl的请求,定位差异点。比如在FastAPI中添加简单的日志中间件:
from fastapi import FastAPI, Request import logging app = FastAPI() logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) @app.middleware("http") async def log_requests(request: Request, call_next): logger.info(f"Received request: {await request.body()}") response = await call_next(request) return response # 你的Ariadne GraphQL配置代码...
这样就能在服务端日志里看到httpx发送的原始请求体,和curl的请求体对比,就能快速找到问题所在。
内容来源于stack exchange
相关产品推荐
相关产品推荐

