HttpURLConnection 默认是 GET,但需显式调用 setRequestMethod("GET") 或不调用该方法;调用 getOutputStream() 会自动切为 POST 并抛 IllegalStateException。

HttpURLConnection 默认是 GET 还是 POST?
默认是 GET,但必须显式调用 setRequestMethod("GET") 或不调用 setRequestMethod —— 否则首次 connect() 或 getOutputStream() 时会隐式设为 GET。一旦尝试写入请求体(比如调用 getOutputStream()),它会自动切换成 POST,哪怕你之前设过 GET,这时会抛 IllegalStateException。
常见错误现象:
java.lang.IllegalStateException: Already connected或
java.lang.IllegalStateException: POST body missing,往往是因为先写了输出流、又去读响应,却忘了设置请求方法或 Content-Length。
- 想发
GET:不调用setRequestMethod,也不调用getOutputStream() - 想发
POST:必须调用setRequestMethod("POST"),且在connect()前设置setDoOutput(true) -
setDoInput(true)默认为true,读响应不需要额外设置;但setDoOutput(false)后再设true会报错
如何正确设置请求头与超时?
setRequestProperty 只能在未连接(connect() 前)调用,否则抛 IllegalStateException。超时值单位是毫秒,且三个超时需分别设置:
-
setConnectTimeout(5000):建立 TCP 连接的上限时间 -
setReadTimeout(10000):从 socket 读取响应数据的单次阻塞上限(不是整个响应) -
setInstanceFollowRedirects(false):禁用自动重定向,否则 302/307 响应会被内部消化,你拿不到原始响应码和 header
常用请求头示例:
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
conn.setRequestProperty("Accept", "application/json");
conn.setRequestProperty("User-Agent", "Java-http-client/1.0");
为什么 getInputStream() 有时抛 IOException?
根本原因:HTTP 状态码 ≥ 400 时,getInputStream() 不可用,必须改用 getErrorStream()。直接调用会抛 IOException: Server returned HTTP response code: 400 这类异常。
立即学习“Java免费学习笔记(深入)”;
正确做法是先查状态码:
int responseCode = conn.getResponseCode();
if (responseCode >= 400) {
is = conn.getErrorStream(); // 而不是 getInputStream()
} else {
is = conn.getInputStream();
}
- 别依赖
getResponseMessage()判断成功与否,它可能返回 null 或空字符串 - 即使状态码是 200,也要检查
Content-Length或用read循环直到返回 -1,避免流提前关闭 - 务必在 finally 块中关闭
InputStream和OutputStream,否则连接可能复用失败或泄漏
POST 发送 JSON 数据要注意什么?
关键点不在“怎么转 JSON”,而在“怎么让服务端正确解析”。HttpURLConnection 不会自动加 Content-Length,如果用 writeBytes 写字符串,得自己算字节长度并调用 setFixedLengthStreamingMode,否则某些服务器(如 Spring Boot 默认配置)会拒绝请求。
推荐方式(避免 chunked 编码):
String json = "{\"name\":\"Alice\",\"age\":30}";
byte[] jsonBytes = json.getBytes(StandardCharsets.UTF_8);
conn.setFixedLengthStreamingMode(jsonBytes.length);
conn.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
os.write(jsonBytes);
}
- 不要用
writeBytes(str),它按平台默认编码写,不可靠;必须用getBytes(UTF_8)显式编码 -
setChunkedStreamingMode(0)会启用分块传输,部分老旧网关或代理不支持 - 如果服务端要求带 Bearer Token,header 必须写成
Authorization: Bearer xxx,漏掉Bearer前缀会导致 401
底层没有连接池,每次 new URL().openConnection() 都是新连接;高频调用务必自己缓存 HttpURLConnection 实例或迁移到 OkHttp。










