Java SpringBoot向FastAPI发送JSON POST请求遇422错误及解码异常求助
问题:SpringBoot发送POST请求到FastAPI出现JSON解析错误
问题重现
SpringBoot请求代码
String requestBody = gson.toJson(sbert); System.out.println(requestBody); // 打印内容在Postman中可正常请求 HttpRequest add_request = HttpRequest.newBuilder() .uri(URI.create("http://localhost:4557/sbert_similarity")) .POST(HttpRequest.BodyPublishers.ofString(requestBody)) .header("Content-Type", "application/json") .build(); HttpResponse<String> response = client.sendAsync(add_request, HttpResponse.BodyHandlers.ofString()).get();
FastAPI服务代码
from fastapi import FastAPI, Request from pydantic import BaseModel from sentence_transformers import SentenceTransformer, util model = SentenceTransformer('all-MiniLM-L6-v2') import pprint as pp import uvicorn from typing import Any app = FastAPI() class Item(BaseModel): user_input: str document: str class ResponseItem(BaseModel): similarity: float @app.post("/sbert_similarity") def check_similarity(item: Item) -> ResponseItem: pp.pprint(item) sentences1 = [item.user_input] sentences2 = [item.document] cosine_score = 0 embeddings1 = model.encode(sentences1, convert_to_tensor=True) embeddings2 = model.encode(sentences2, convert_to_tensor=True) cosine_score = util.cos_sim(embeddings1, embeddings2) return { "similarity" : cosine_score } if __name__=="__main__": uvicorn.run("similarity_server:app",host='0.0.0.0', port=4557, reload=True, workers=3)
错误现象
- SpringBoot请求返回:
{"detail":[{"loc":["body"],"msg":"field required","type":"value_error.missing"}]}
- FastAPI日志显示:
INFO: 127.0.0.1:65066 - "POST /sbert_similarity HTTP/1.1" 422 Unprocessable Entity - 添加测试接口
/sbert_similarity_v3后,请求触发JSONDecodeError,疑似发送null或无效JSON。 - 相同请求体在Postman中可正常调用接口。
原因排查与解决方案
1. 字段命名不匹配(最可能原因)
FastAPI的Item类字段为下划线命名(user_input),若Java的sbert类字段是驼峰命名(如userInput),默认Gson会序列化为"userInput",导致FastAPI无法识别必填字段,返回field required错误。
解决方法:配置Gson使用下划线命名策略:
Gson gson = new GsonBuilder() .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .create(); String requestBody = gson.toJson(sbert);
2. 请求头Content-Type重复或无效
Java的HttpRequest.header()方法会添加头而非覆盖,若客户端已有重复的Content-Type头,会引发FastAPI解析异常。
解决方法:改用setHeader()确保唯一的Content-Type,并明确编码:
HttpRequest add_request = HttpRequest.newBuilder() .uri(URI.create("http://localhost:4557/sbert_similarity")) .POST(HttpRequest.BodyPublishers.ofString(requestBody)) .setHeader("Content-Type", "application/json; charset=utf-8") .build();
3. 验证实际发送的请求体
修改FastAPI测试接口,打印原始请求体,确认是否与本地打印内容一致:
@app.post("/sbert_similarity_v3") async def check_similarity(request: Request) -> Any: content_type = request.headers.get('Content-Type') if content_type is None: return 'No Content-Type provided.' elif 'application/json' in content_type: try: raw_body = await request.body() print(f"Received raw body: {raw_body.decode('utf-8')}") json_data = await request.json() return json_data except Exception as e: print(f"Error: {str(e)}") return f'Invalid request: {str(e)}' else: return 'Content-Type not supported.'
查看FastAPI控制台输出,若原始body为空或格式错误,排查Gson序列化逻辑或sbert对象的字段值是否正确。
4. 异步请求阻塞问题
sendAsync(...).get()会阻塞线程等待结果,若请求未完整发送就被中断,可能导致body不完整。可改用同步请求测试:
HttpResponse<String> response = client.send(add_request, HttpResponse.BodyHandlers.ofString());
内容的提问来源于stack exchange,提问作者Steveit
相关产品推荐
相关产品推荐

