1. 概述
本文将介绍在Java中执行HTTP请求的基础方法——使用内置的 HttpUrlConnection
类。
⚠️ 注意:从JDK 11开始,Java提供了新的 HttpClient API
作为 HttpUrlConnection
的替代方案。但本文聚焦于经典的 HttpUrlConnection
实现。
2. HttpUrlConnection
详解
HttpUrlConnection
类允许我们在不依赖任何第三方库的情况下执行基础HTTP请求。所有必需的类都位于 java.net
包中。
✅ 优点:
- 零外部依赖
- JDK原生支持
❌ 缺点:
- 代码比现代HTTP库更繁琐
- 缺少高级功能(如专门的Header添加或认证方法)
3. 创建请求
通过 URL
类的 openConnection()
方法创建 HttpUrlConnection
实例。注意:此方法仅创建连接对象,尚未建立实际连接。
通过设置 requestMethod
属性指定请求类型(GET/POST/HEAD/OPTIONS/PUT/DELETE/TRACE):
URL url = new URL("http://example.com");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
4. 添加请求参数
若需添加参数,**必须将 doOutput
设为 true
,然后将 param1=value¶m2=value
格式的字符串写入 OutputStream
**:
Map<String, String> parameters = new HashMap<>();
parameters.put("param1", "val");
con.setDoOutput(true);
DataOutputStream out = new DataOutputStream(con.getOutputStream());
out.writeBytes(ParameterStringBuilder.getParamsString(parameters));
out.flush();
out.close();
为方便参数转换,我们创建了工具类 ParameterStringBuilder
,其静态方法 getParamsString()
将 Map
转换为所需格式:
public class ParameterStringBuilder {
public static String getParamsString(Map<String, String> params)
throws UnsupportedEncodingException{
StringBuilder result = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
result.append("=");
result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
result.append("&");
}
String resultString = result.toString();
return resultString.length() > 0
? resultString.substring(0, resultString.length() - 1)
: resultString;
}
}
5. 设置请求头
通过 setRequestProperty()
方法添加请求头:
con.setRequestProperty("Content-Type", "application/json");
读取响应头使用 getHeaderField()
:
String contentType = con.getHeaderField("Content-Type");
6. 配置超时
HttpUrlConnection
支持设置连接超时和读取超时。这些值定义了等待服务器连接建立或数据可读的时间间隔。
使用 setConnectTimeout()
和 setReadTimeout()
配置:
con.setConnectTimeout(5000); // 5秒连接超时
con.setReadTimeout(5000); // 5秒读取超时
7. 处理Cookie
java.net
包提供了 CookieManager
和 HttpCookie
等类简化Cookie操作。
读取响应中的Cookie:
String cookiesHeader = con.getHeaderField("Set-Cookie");
List<HttpCookie> cookies = HttpCookie.parse(cookiesHeader);
将Cookie添加到Cookie存储:
cookies.forEach(cookie -> cookieManager.getCookieStore().add(null, cookie));
检查是否存在名为 username
的Cookie,若不存在则添加值为 john
:
Optional<HttpCookie> usernameCookie = cookies.stream()
.findAny().filter(cookie -> cookie.getName().equals("username"));
if (usernameCookie == null) {
cookieManager.getCookieStore().add(null, new HttpCookie("username", "john"));
}
在请求中添加Cookie(需先断开并重建连接):
con.disconnect();
con = (HttpURLConnection) url.openConnection();
con.setRequestProperty("Cookie",
StringUtils.join(cookieManager.getCookieStore().getCookies(), ";"));
8. 处理重定向
通过 setInstanceFollowRedirects()
控制是否自动跟随重定向:
con.setInstanceFollowRedirects(false); // 禁用自动重定向
全局控制重定向行为:
HttpUrlConnection.setFollowRedirects(false); // 所有连接禁用
默认启用自动重定向。当收到301/302状态码时,可手动处理:
if (status == HttpURLConnection.HTTP_MOVED_TEMP
|| status == HttpURLConnection.HTTP_MOVED_PERM) {
String location = con.getHeaderField("Location");
URL newUrl = new URL(location);
con = (HttpURLConnection) newUrl.openConnection();
}
9. 读取响应
通过解析 HttpUrlConnection
的 InputStream
读取响应内容。
执行请求(调用以下任一方法):
getResponseCode()
connect()
getInputStream()
getOutputStream()
int status = con.getResponseCode();
读取响应内容到字符串:
BufferedReader in = new BufferedReader(
new InputStreamReader(con.getInputStream()));
String inputLine;
StringBuffer content = new StringBuffer();
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
}
in.close();
关闭连接:
con.disconnect();
10. 处理失败请求的响应
请求失败时,直接读取 getInputStream()
会抛异常。**应改用 getErrorStream()
**:
根据HTTP状态码选择流:
int status = con.getResponseCode();
Reader streamReader = null;
if (status > 299) {
streamReader = new InputStreamReader(con.getErrorStream());
} else {
streamReader = new InputStreamReader(con.getInputStream());
}
后续读取方式与第9节相同。
11. 构建完整响应
HttpUrlConnection
无法直接获取完整响应,但可组合其提供的方法构建:
public class FullResponseBuilder {
public static String getFullResponse(HttpURLConnection con) throws IOException {
StringBuilder fullResponseBuilder = new StringBuilder();
// 读取状态和消息
fullResponseBuilder.append(con.getResponseCode())
.append(" ")
.append(con.getResponseMessage())
.append("\n");
// 读取头部
con.getHeaderFields().entrySet().stream()
.filter(entry -> entry.getKey() != null)
.forEach(entry -> {
fullResponseBuilder.append(entry.getKey()).append(": ");
List headerValues = entry.getValue();
Iterator it = headerValues.iterator();
if (it.hasNext()) {
fullResponseBuilder.append(it.next());
while (it.hasNext()) {
fullResponseBuilder.append(", ").append(it.next());
}
}
fullResponseBuilder.append("\n");
});
// 读取响应内容(根据状态选择流)
// ...(此处省略流读取代码,逻辑同第10节)
return fullResponseBuilder.toString();
}
}
12. 总结
本文展示了使用 HttpUrlConnection
执行HTTP请求的核心方法。虽然代码略显繁琐,但作为JDK原生方案,在无第三方依赖的场景下仍是可靠选择。
完整示例代码见 GitHub仓库