Java 11 HttpRequest POST请求无法被FastAPI服务识别问题
Java 11 HttpClient 请求FastAPI返回422错误的解决方法
使用Java 11的HttpClient发送POST请求到FastAPI接口时,返回422状态码,提示请求体缺失,但curl和Java旧版HttpURLConnection方式都能正常请求。
相关代码
FastAPI服务代码
# 启动命令:uvicorn simle_ws:app --host=0.0.0.0 --port=8001 from datetime import date import pandas as pd from fastapi import FastAPI from pydantic import BaseModel class Dataset(BaseModel): key: str value: float app = FastAPI() @app.post("/test/") async def test(dataset: Dataset): return dataset
curl请求(正常工作)
curl -X 'POST' \ 'http://localhost:8001/test/' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"key": "age","value": 43}'
返回结果:{"key":"age","value":42.0}
Java 11前的请求方式(正常工作)
@Test void testPree11() throws IOException { URL url = new URL("http://localhost:8001/test/"); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestMethod("POST"); con.setRequestProperty("Content-Type", "application/json"); con.setRequestProperty("Accept", "application/json"); con.setDoOutput(true); String jsonInputString = """{ "key": "age", "value": 42 } """; try (OutputStream os = con.getOutputStream()) { byte[] input = jsonInputString.getBytes(StandardCharsets.UTF_8); os.write(input, 0, input.length); } try (BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8))) { StringBuilder response = new StringBuilder(); String responseLine; while ((responseLine = br.readLine()) != null) { response.append(responseLine.trim()); } assertEquals(200, con.getResponseCode()); String expected = """{ "key":"age","value":42.0 """; assertEquals(expected.trim(), response.toString().trim()); } }
Java 11 HttpClient请求方式(失败)
@Test void testPost11() throws URISyntaxException, IOException, InterruptedException { String jsonInputString = """{ "key": "age", "value": 42 } """; HttpRequest request = HttpRequest.newBuilder() .uri(new URI("http://localhost:8001/test/")) .header("Accept", "application/json") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(jsonInputString)) .build(); HttpClient.Builder clientBuilder = HttpClient.newBuilder(); HttpClient client = clientBuilder.build(); HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString()); assertEquals(200, response.statusCode()); String expected = """{ "key":"age","value":42.0 """; assertEquals(expected.trim(), response.body().trim()); }
返回状态码422,响应内容:
{ "detail": [ { "type": "missing", "loc": [ "body" ], "msg": "Field required", "input": null } ] }
问题原因
Java 11的HttpRequest.BodyPublishers.ofString(jsonInputString)方法会自动为请求添加Content-Type: text/plain;charset=utf-8头,覆盖掉手动设置的Content-Type: application/json。FastAPI接收到text/plain类型的请求后,不会将其解析为JSON请求体,因此提示请求体缺失。
解决方案
有两种可行的解决方式:
方式一:指定字符集并覆盖Content-Type头
使用ofString时指定UTF-8字符集,再通过setHeader方法覆盖自动添加的Content-Type头:
HttpRequest request = HttpRequest.newBuilder() .uri(new URI("http://localhost:8001/test/")) .header("Accept", "application/json") .POST(HttpRequest.BodyPublishers.ofString(jsonInputString, StandardCharsets.UTF_8)) .setHeader("Content-Type", "application/json") // 覆盖自动添加的Content-Type .build();
方式二:使用字节数组发送请求
将JSON字符串转为UTF-8字节数组,通过BodyPublishers.ofByteArray发送,避免自动添加Content-Type头:
HttpRequest request = HttpRequest.newBuilder() .uri(new URI("http://localhost:8001/test/")) .header("Accept", "application/json") .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofByteArray(jsonInputString.getBytes(StandardCharsets.UTF_8))) .build();
验证
修改后重新运行测试,请求将返回200状态码,响应内容与预期一致。
内容的提问来源于stack exchange,提问作者Johan Walter
相关产品推荐
相关产品推荐

