Java 怎么发送 HTTP 请求:GET、POST、Header 和 JSON 请求体
围绕接口调试和后端对接,讲清 Java 使用 HttpClient 发送 GET、POST、Header、JSON 请求体的方法,以及状态码、响应体和异常排查流程。
相关工具
先把接口文档里的信息拆清楚
Java 发送 HTTP 请求前,先看接口文档里的四类信息:请求方法、URL、参数、Header。请求方法常见是 GET 和 POST;URL 可能带 query 参数;Header 里可能有 Authorization、Content-Type、Accept、User-Agent;请求体可能是 JSON、表单或文件。
很多接口调不通,不是 Java 发送请求的能力不够,而是请求和文档不一致。比如文档要求 POST JSON,你却用表单提交;文档要求 Bearer Token,你只传了 Token 本身;文档要求参数放在 URL 上,你放到了 JSON body 里。
调试时不要只盯着代码,应该把最终发出去的 URL、Header、Body 都打印或记录。和接口文档逐项对照,往往比反复换库更有效。Java 11 以后自带 HttpClient,简单接口不一定需要额外依赖。
发送 GET 请求
Java 11 的 HttpClient 可以这样发送 GET 请求:
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/search?keyword=python&page=1"))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());GET 参数通常拼在 URL 后面。如果参数里有中文、空格或特殊字符,要做 URL 编码。不要手工拼复杂参数,否则很容易漏掉编码。可以先用 URL 工具检查最终 URL 是否符合预期。
statusCode 是 HTTP 状态码。200 不一定代表业务成功,但 400、401、403、404、500 这类状态码能帮助你快速判断问题方向。GET 请求失败时,先检查 URL 是否正确、参数名是否拼错、是否需要认证 Header。
发送 POST JSON 请求
POST JSON 请求要设置 Content-Type,并把 JSON 字符串放入请求体:
String json = "{\"name\":\"张三\",\"age\":28}";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer YOUR_TOKEN")
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());这里最容易错的是 JSON 字符串。Java 字符串里的双引号要转义,所以手写 JSON 会比较难看。正式项目里通常用 Jackson 把对象转成 JSON 字符串,而不是手动拼接。手动拼接容易出现引号、逗号、特殊字符转义问题。
如果接口返回参数错误,先把请求体复制到 JSON 工具里校验。确认 JSON 合法后,再检查字段名、字段类型和 Content-Type。字段名大小写也要和文档一致,userId 和 user_id 不是一个字段。
用 Jackson 生成 JSON 请求体
如果项目里已经有 Jackson,可以这样生成请求体:
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> payload = Map.of(
"name", "张三",
"age", 28,
"city", "杭州"
);
String json = mapper.writeValueAsString(payload);这样比手动拼 JSON 安全。比如中文、引号、换行、特殊字符都会由 JSON 库处理。请求体字段多的时候,建议定义 DTO 类,再序列化成 JSON。Map 适合临时脚本和简单调试,DTO 更适合正式项目。
发送前可以打印 json,并粘到 JSON 格式化工具里看一眼。尤其是接口要求嵌套结构时,比如 data 里有 list,或者 items 是数组,格式化查看能避免层级写错。
Header 和响应怎么排查
Header 问题很常见。Authorization 是否带 Bearer?Content-Type 是否是 application/json?Accept 是否需要 application/json?某些接口还要求 X-Request-Id、时间戳、签名或客户端标识。Header 漏一个,可能直接 401 或 403。
响应也要分层看。第一层是 HTTP 状态码,第二层是响应 Header,第三层是响应体。如果响应体是 JSON,再看业务 code、message 和 data。不要只看 body,也不要只看 statusCode。很多系统 HTTP 200 但业务 code 失败,或者 HTTP 400 但 body 里给了详细错误原因。
调试阶段可以打印 response.headers()。如果服务端返回 Content-Type 不是 application/json,就不要直接按 JSON 解析。网关错误、鉴权失败、限流页面都可能返回 HTML 或纯文本。
一套实用接口调用流程
第一步,用 API 调试工具手动跑通接口,确认方法、URL、Header 和 Body 没问题。第二步,把同样参数翻译成 Java HttpClient 代码。第三步,打印最终请求体和响应状态。第四步,格式化响应 JSON,确认业务字段。第五步,再封装成方法。
如果接口需要签名,先不要把签名逻辑和请求逻辑写在一起。先单独生成签名,和服务端示例或 HMAC 工具核对一致,再放入请求 Header。这样排查范围更小。否则你不知道失败是请求问题、签名问题还是参数问题。
正式代码里还要考虑超时、重试和日志。HttpClient 可以设置 connectTimeout,请求也可以设置 timeout。重试不要无脑重试所有请求,查询类接口可以谨慎重试,创建订单、扣款、发券这类有副作用的接口必须考虑幂等键,否则可能造成重复操作。
日志也不要把完整 Token、Secret、手机号、身份证等敏感信息打出来。可以记录请求路径、状态码、耗时、业务错误码和请求 ID。这样既能排查问题,也不会把敏感数据暴露在日志里。
如果接口用于线上任务,建议把失败响应保存一小段样本。只记录一句请求失败,后面很难判断是参数问题、权限问题还是服务端异常。保留状态码、错误码和请求 ID,排查效率会高很多。
工具帮的 API 调试、Headers 解析、JSON 格式化和 URL 解析工具适合在写 Java 代码前后做核对。代码负责集成,工具负责看清结构和定位错误。对新手来说,这种流程比直接复制一大段代码更稳。
常见问题
Java 发送 HTTP 请求必须用第三方库吗?
不是。Java 11 以后自带 HttpClient,常规 GET、POST、Header 和 JSON 请求都能处理。
POST JSON 为什么服务端收不到参数?
常见原因是 Content-Type 没设为 application/json,或者把 JSON 当表单提交了。
接口返回 200 就一定成功吗?
不一定。还要看响应体里的业务 code、success、message 等字段。