Android HTTP请求方式:HttpURLConnection
在 Android 中,HttpURLConnection
是 Java 提供的原生 HTTP 客户端,用于执行网络请求。它适用于简单的 HTTP 请求场景,如 GET、POST 等。以下是使用 HttpURLConnection
进行 Android HTTP 请求的详细学习指南,包括请求方式、代码示例、注意事项和实践建议。
一、HttpURLConnection 概述
- 定义:
HttpURLConnection
是 Java 标准库中的类,继承自URLConnection
,用于处理 HTTP/HTTPS 请求。 - 特点:
- 支持 GET、POST、PUT、DELETE 等 HTTP 方法。
- 可设置请求头、请求体、超时时间。
- 支持处理响应数据和状态码。
- 原生支持 HTTPS(通过 SSL/TLS)。
- 适用场景:简单网络请求、学习 HTTP 基础、不依赖第三方库的场景。
- 局限性:
- 代码较为冗长,异步处理复杂。
- 缺少高级功能(如连接池、拦截器),推荐生产环境中使用 OkHttp 或 Retrofit。
二、HttpURLConnection 的核心使用步骤
以下是使用 HttpURLConnection
执行 HTTP 请求的基本步骤:
- 声明网络权限:
在AndroidManifest.xml
中添加:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- 创建 URL 对象:
指定目标服务器地址。
URL url = new URL("https://api.example.com/data");
- 打开连接:
使用openConnection()
创建HttpURLConnection
实例。
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- 配置请求:
设置请求方法、请求头、超时时间等。
conn.setRequestMethod("GET"); // 或 "POST"、"PUT"、"DELETE"
conn.setConnectTimeout(5000); // 连接超时,单位毫秒
conn.setReadTimeout(5000); // 读取超时,单位毫秒
conn.setRequestProperty("Content-Type", "application/json");
- 发送请求(POST/PUT 需要):
如果是 POST 或 PUT,写入请求体数据。
conn.setDoOutput(true); // 允许输出
OutputStream os = conn.getOutputStream();
os.write("{\"key\":\"value\"}".getBytes());
os.flush();
os.close();
- 处理响应:
检查状态码,读取响应数据或处理错误。
int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream in = conn.getInputStream();
// 读取数据
} else {
InputStream err = conn.getErrorStream();
// 处理错误
}
- 关闭连接:
释放资源。
conn.disconnect();
三、常见 HTTP 请求方式示例
以下是使用 HttpURLConnection
实现 GET 和 POST 请求的详细代码示例。
1. GET 请求
GET 请求用于从服务器获取资源,通常不包含请求体。
public String doGetRequest(String urlString) {
HttpURLConnection conn = null;
StringBuilder response = new StringBuilder();
try {
// 1. 创建 URL 和连接
URL url = new URL(urlString);
conn = (HttpURLConnection) url.openConnection();
// 2. 配置请求
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.setRequestProperty("Accept", "application/json");
// 添加认证头(可选)
conn.setRequestProperty("Authorization", "Bearer your_token_here");
// 3. 获取响应
int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
return response.toString();
} else {
// 处理错误
return "Error: " + responseCode;
}
} catch (IOException e) {
e.printStackTrace();
return "Exception: " + e.getMessage();
} finally {
// 4. 关闭连接
if (conn != null) {
conn.disconnect();
}
}
}
- 使用示例(在子线程或 AsyncTask 中调用):
new Thread(() -> {
String result = doGetRequest("https://api.example.com/data");
// 在主线程更新 UI
runOnUiThread(() -> {
Log.d("Response", result);
});
}).start();
2. POST 请求
POST 请求用于向服务器提交数据,包含请求体。
public String doPostRequest(String urlString, String jsonBody) {
HttpURLConnection conn = null;
StringBuilder response = new StringBuilder();
try {
// 1. 创建 URL 和连接
URL url = new URL(urlString);
conn = (HttpURLConnection) url.openConnection();
// 2. 配置请求
conn.setRequestMethod("POST");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Accept", "application/json");
conn.setDoOutput(true); // 允许写入请求体
// 3. 写入请求体
OutputStream os = conn.getOutputStream();
os.write(jsonBody.getBytes("UTF-8"));
os.flush();
os.close();
// 4. 获取响应
int responseCode = conn.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK || responseCode == HttpURLConnection.HTTP_CREATED) {
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
return response.toString();
} else {
BufferedReader errorReader = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
String line;
while ((line = errorReader.readLine()) != null) {
response.append(line);
}
errorReader.close();
return "Error: " + responseCode + " - " + response.toString();
}
} catch (IOException e) {
e.printStackTrace();
return "Exception: " + e.getMessage();
} finally {
// 5. 关闭连接
if (conn != null) {
conn.disconnect();
}
}
}
- 使用示例(在子线程中调用):
new Thread(() -> {
String jsonBody = "{\"username\":\"user\",\"password\":\"pass\"}";
String result = doPostRequest("https://api.example.com/login", jsonBody);
// 在主线程更新 UI
runOnUiThread(() -> {
Log.d("Response", result);
});
}).start();
3. 其他请求方法(PUT、DELETE)
PUT 和 DELETE 的实现与 POST 类似,只需修改 setRequestMethod
:
conn.setRequestMethod("PUT"); // 或 "DELETE"
四、处理响应头与错误
1. 读取响应头
Map<String, List<String>> headers = conn.getHeaderFields();
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
Log.d("Header", entry.getKey() + ": " + entry.getValue());
}
// 获取特定头
String contentType = conn.getHeaderField("Content-Type");
String setCookie = conn.getHeaderField("Set-Cookie");
2. 处理错误
- 检查状态码:
int responseCode = conn.getResponseCode();
if (responseCode >= 400) {
InputStream errorStream = conn.getErrorStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(errorStream));
StringBuilder error = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
error.append(line);
}
reader.close();
Log.e("Error", "Code: " + responseCode + ", Message: " + error.toString());
}
3. 处理 HTTPS
HttpURLConnection
默认支持 HTTPS。如果遇到自签名证书问题,需自定义 TrustManager
(生产环境谨慎使用):
// 示例:信任所有证书(仅用于调试)
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() { return null; }
public void checkClientTrusted(X509Certificate[] certs, String authType) {}
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
五、异步处理
Android 不允许在主线程执行网络操作,需使用异步机制:
1. 使用 Thread
如上述示例,直接在子线程中执行请求。
2. 使用 AsyncTask(已废弃)
public class NetworkTask extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... params) {
return doGetRequest(params[0]);
}
@Override
protected void onPostExecute(String result) {
Log.d("Response", result);
}
}
3. 使用 Kotlin 协程(推荐)
suspend fun doGetRequest(urlString: String): String = withContext(Dispatchers.IO) {
val url = URL(urlString)
val conn = url.openConnection() as HttpURLConnection
try {
conn.requestMethod = "GET"
conn.setRequestProperty("Accept", "application/json")
val responseCode = conn.responseCode
if (responseCode == HttpURLConnection.HTTP_OK) {
conn.inputStream.bufferedReader().use { it.readText() }
} else {
"Error: $responseCode"
}
} finally {
conn.disconnect()
}
}
// 调用
lifecycleScope.launch {
val result = doGetRequest("https://api.example.com/data")
Log.d("Response", result)
}
六、注意事项
- 子线程执行:
- 网络操作必须在子线程运行,否则抛出
NetworkOnMainThreadException
。
- 资源释放:
- 始终调用
conn.disconnect()
释放连接。 - 关闭
InputStream
、OutputStream
和Reader
。
- 错误处理:
- 处理
IOException
、超时、状态码错误。 - 检查网络状态:
java ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = cm.getActiveNetworkInfo(); if (networkInfo == null || !networkInfo.isConnected()) { // 无网络 }
- HTTPS 安全:
- 生产环境中避免信任所有证书,使用证书固定(Certificate Pinning)。
- 性能优化:
- 设置合理的超时时间(
setConnectTimeout
、setReadTimeout
)。 - 使用 Gzip 压缩(添加请求头
Accept-Encoding: gzip
):java conn.setRequestProperty("Accept-Encoding", "gzip"); InputStream in = conn.getInputStream(); if ("gzip".equals(conn.getContentEncoding())) { in = new GZIPInputStream(in); }
七、学习建议与实践
- 学习路径:
- 理解 HTTP 协议基础(请求/响应、方法、状态码、头)。
- 掌握
HttpURLConnection
的基本使用(GET、POST)。 - 学习异步处理(Thread、AsyncTask、协程)。
- 深入响应头处理(Cookie、缓存)。
- 对比 OkHttp 和 Retrofit,了解
HttpURLConnection
的局限性。
- 实践项目:
- 调用公开 API(如 OpenWeatherMap),实现 GET 请求获取天气数据。
- 实现登录功能,使用 POST 请求发送 JSON 数据。
- 处理 Cookie,保存
Set-Cookie
并在后续请求中发送。
- 调试工具:
- 使用 Postman 测试 API,验证请求/响应。
- 使用 Charles 或 Android Studio 的 Network Profiler 分析请求。
- 推荐资源:
- 官方文档:https://developer.android.com/reference/java/net/HttpURLConnection
- MDN HTTP 文档:https://developer.mozilla.org/en-US/docs/Web/HTTP
- 实践 API:https://api.github.com/ 或 https://openweathermap.org/api
八、总结
- HttpURLConnection 是 Android 原生的 HTTP 客户端,适合简单请求。
- 核心步骤:创建 URL、配置连接、设置请求头/体、处理响应、释放资源。
- 请求方式:
- GET:获取数据,设置请求头(如
Accept
)。 - POST:提交数据,写入请求体(如 JSON)。
- 注意事项:异步处理、资源释放、错误处理、HTTPS 安全。
- 进阶建议:学习 OkHttp 和 Retrofit 以替代
HttpURLConnection
,实现更高效的网络编程。
如果需要更详细的代码示例(如文件上传、处理特定头)或针对某个场景的深入讲解,请告诉我!