您好,登录后才能下订单哦!
# OkHttp怎么用:从入门到精通的全方位指南
OkHttp是Square公司开发的一个高效、现代的HTTP客户端,支持Android和Java应用程序。它简化了HTTP请求的发送和响应处理,提供了连接池、GZIP压缩、响应缓存等强大功能。本文将全面介绍OkHttp的使用方法,从基础概念到高级特性,帮助你掌握这个强大的网络库。
## 目录
1. [OkHttp简介](#okhttp简介)
2. [环境配置与基本使用](#环境配置与基本使用)
3. [同步与异步请求](#同步与异步请求)
4. [请求与响应详解](#请求与响应详解)
5. [拦截器与自定义功能](#拦截器与自定义功能)
6. [文件上传与下载](#文件上传与下载)
7. [WebSocket通信](#websocket通信)
8. [连接池与性能优化](#连接池与性能优化)
9. [HTTPS与安全配置](#https与安全配置)
10. [常见问题与解决方案](#常见问题与解决方案)
11. [最佳实践](#最佳实践)
12. [总结](#总结)
<a id="okhttp简介"></a>
## 1. OkHttp简介
### 1.1 OkHttp是什么
OkHttp是一个高效的HTTP客户端,具有以下特点:
- 支持HTTP/2,允许对同一主机的所有请求共享一个套接字
- 连接池减少请求延迟(如果HTTP/2不可用)
- 透明的GZIP压缩减小下载大小
- 响应缓存完全避免重复请求的网络开销
### 1.2 OkHttp的优势
与其他HTTP客户端相比,OkHttp具有明显优势:
- **性能优异**:连接池和请求复用显著提高性能
- **功能全面**:支持同步/异步调用、文件上传下载、WebSocket等
- **扩展性强**:拦截器机制允许自定义网络行为
- **社区活跃**:由Square公司维护,更新及时,文档完善
### 1.3 适用场景
OkHttp适用于:
- Android应用网络请求
- Java后端服务的HTTP客户端
- 需要高效网络通信的任何场景
<a id="环境配置与基本使用"></a>
## 2. 环境配置与基本使用
### 2.1 添加依赖
#### Android项目
```gradle
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.3</version>
</dependency>
OkHttpClient client = new OkHttpClient();
// 创建请求
Request request = new Request.Builder()
.url("https://api.example.com/data")
.build();
// 发送请求并获取响应
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
System.out.println(responseBody);
}
}
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();
同步请求会阻塞当前线程直到收到响应:
Request request = new Request.Builder()
.url("https://api.example.com/data")
.build();
try (Response response = client.newCall(request).execute()) {
// 处理响应
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0; i < responseHeaders.size(); i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(response.body().string());
}
异步请求不会阻塞UI线程,通过回调处理响应:
Request request = new Request.Builder()
.url("https://api.example.com/data")
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
try (ResponseBody responseBody = response.body()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
Headers responseHeaders = response.headers();
for (int i = 0; i < responseHeaders.size(); i++) {
System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
}
System.out.println(responseBody.string());
}
}
});
Request request = new Request.Builder()
.url("https://api.example.com/data")
.header("User-Agent", "OkHttp Example")
.addHeader("Accept", "application/json")
.build();
MediaType JSON = MediaType.get("application/json; charset=utf-8");
String json = "{\"username\":\"admin\",\"password\":\"123456\"}";
RequestBody body = RequestBody.create(json, JSON);
Request request = new Request.Builder()
.url("https://api.example.com/login")
.post(body)
.build();
Response response = client.newCall(request).execute();
// 获取单个响应头
String server = response.header("Server");
// 获取所有响应头
Headers headers = response.headers();
for (String name : headers.names()) {
System.out.println(name + ": " + headers.get(name));
}
// 获取字符串形式响应体
String responseBody = response.body().string();
// 获取字节流形式响应体
InputStream inputStream = response.body().byteStream();
// 获取字节数组形式响应体
byte[] bytes = response.body().bytes();
RequestBody formBody = new FormBody.Builder()
.add("username", "admin")
.add("password", "123456")
.build();
Request request = new Request.Builder()
.url("https://api.example.com/login")
.post(formBody)
.build();
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("title", "Square Logo")
.addFormDataPart("image", "logo.png",
RequestBody.create(new File("logo.png"), MediaType.parse("image/png")))
.build();
Request request = new Request.Builder()
.header("Authorization", "Bearer " + token)
.url("https://api.example.com/upload")
.post(requestBody)
.build();
拦截器可以监控、重写和重试请求:
class LoggingInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
System.out.printf("Sending request %s on %s%n%s%n",
request.url(), chain.connection(), request.headers());
Response response = chain.proceed(request);
long t2 = System.nanoTime();
System.out.printf("Received response for %s in %.1fms%n%s%n",
response.request().url(), (t2 - t1) / 1e6d, response.headers());
return response;
}
}
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new LoggingInterceptor())
.build();
网络拦截器可以访问更多请求信息,如Connection:
class NetworkLoggingInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
// 实现类似LoggingInterceptor但可以访问更多网络层信息
}
}
OkHttpClient client = new OkHttpClient.Builder()
.addNetworkInterceptor(new NetworkLoggingInterceptor())
.build();
MediaType mediaType = MediaType.parse("text/plain");
RequestBody requestBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("file", "filename.txt",
RequestBody.create(new File("path/to/file.txt"), mediaType))
.build();
Request request = new Request.Builder()
.url("https://api.example.com/upload")
.post(requestBody)
.build();
class ProgressRequestBody extends RequestBody {
private final File file;
private final ProgressListener listener;
public ProgressRequestBody(File file, ProgressListener listener) {
this.file = file;
this.listener = listener;
}
@Override
public void writeTo(BufferedSink sink) throws IOException {
Source source = Okio.source(file);
Buffer buffer = new Buffer();
long total = file.length();
long uploaded = 0;
try {
long read;
while ((read = source.read(buffer, 2048)) != -1) {
sink.write(buffer, read);
uploaded += read;
listener.onProgress(uploaded, total);
}
} finally {
source.close();
}
}
}
// 使用自定义RequestBody
RequestBody requestBody = new ProgressRequestBody(file, (uploaded, total) -> {
double progress = 100.0 * uploaded / total;
System.out.printf("Upload progress: %.1f%%%n", progress);
});
Request request = new Request.Builder()
.url("https://example.com/file.zip")
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
try (InputStream inputStream = response.body().byteStream();
FileOutputStream fileOutputStream = new FileOutputStream("local.zip")) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, bytesRead);
}
}
}
class ProgressResponseBody extends ResponseBody {
private final ResponseBody responseBody;
private final ProgressListener listener;
private BufferedSource bufferedSource;
public ProgressResponseBody(ResponseBody responseBody, ProgressListener listener) {
this.responseBody = responseBody;
this.listener = listener;
}
@Override
public BufferedSource source() {
if (bufferedSource == null) {
bufferedSource = Okio.buffer(source(responseBody.source()));
}
return bufferedSource;
}
private Source source(Source source) {
return new ForwardingSource(source) {
long totalBytesRead = 0L;
@Override
public long read(Buffer sink, long byteCount) throws IOException {
long bytesRead = super.read(sink, byteCount);
totalBytesRead += bytesRead != -1 ? bytesRead : 0;
listener.onProgress(totalBytesRead, responseBody.contentLength());
return bytesRead;
}
};
}
}
// 使用拦截器添加进度监听
client = new OkHttpClient.Builder()
.addNetworkInterceptor(chain -> {
Response originalResponse = chain.proceed(chain.request());
return originalResponse.newBuilder()
.body(new ProgressResponseBody(originalResponse.body(), (bytesRead, contentLength) -> {
double progress = 100.0 * bytesRead / contentLength;
System.out.printf("Download progress: %.1f%%%n", progress);
}))
.build();
})
.build();
WebSocket提供了全双工通信通道:
Request request = new Request.Builder()
.url("wss://echo.websocket.org")
.build();
WebSocketListener listener = new WebSocketListener() {
@Override
public void onOpen(WebSocket webSocket, Response response) {
System.out.println("WebSocket connected");
webSocket.send("Hello WebSocket!");
}
@Override
public void onMessage(WebSocket webSocket, String text) {
System.out.println("Received message: " + text);
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
System.out.println("Closing: " + code + " " + reason);
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
t.printStackTrace();
}
};
WebSocket webSocket = client.newWebSocket(request, listener);
// 发送文本消息
webSocket.send("Hello WebSocket!");
// 发送二进制消息
webSocket.send(ByteString.of(new byte[] {0x01, 0x02, 0x03}));
// 接收消息
@Override
public void onMessage(WebSocket webSocket, String text) {
// 处理文本消息
}
@Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
// 处理二进制消息
}
// 正常关闭
webSocket.close(1000, "Goodbye!");
// 强制关闭
webSocket.cancel();
ConnectionPool connectionPool = new ConnectionPool(
5, // 最大空闲连接数
5, // 保持时间(分钟)
TimeUnit.MINUTES);
OkHttpClient client = new OkHttpClient.Builder()
.connectionPool(connectionPool)
.build();
int cacheSize = 10 * 1024 * 1024; // 10MB
Cache cache = new Cache(new File("cacheDir"), cacheSize);
OkHttpClient client = new OkHttpClient.Builder()
.cache(cache)
.build();
Dns dns = hostname -> {
// 自定义DNS解析逻辑
if (hostname.equals("api.example.com")) {
return Arrays.asList(InetAddress.getByName("1.2.3.4"));
}
return Dns.SYSTEM.lookup(hostname);
};
OkHttpClient client = new OkHttpClient.Builder()
.dns(dns)
.build();
OkHttp默认支持HTTPS,无需额外配置:
Request request = new Request.Builder()
.url("https://example.com")
.build();
X509TrustManager trustManager = new X509TrustManager() {
@Override public void checkClientTrusted(X509Certificate[] chain, String authType) {}
@Override public void checkServerTrusted(X509Certificate[] chain, String authType) {}
@Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
};
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[] { trustManager }, new SecureRandom());
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory(), trustManager)
.hostnameVerifier((hostname, session) -> true)
.build();
”`java // 从assets加载证书 InputStream certInputStream = context.getAssets().open(“my_cert.pem”); CertificateFactory certificateFactory = CertificateFactory.getInstance(“X.509”); Certificate cert = certificateFactory.generateCertificate(certInputStream);
// 创建KeyStore String keyStoreType = KeyStore.getDefaultType(); KeyStore keyStore = KeyStore.getInstance(keyStoreType); keyStore.load(null, null); keyStore.setCertificateEntry(“ca”, cert);
// 创建TrustManager String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); tmf.init(keyStore);
// 创建SSLContext SSLContext sslContext = SSLContext.getInstance(“TLS”); sslContext.init(null, tmf.getTrustManagers(), null);
OkHttpClient client = new OkHttpClient.Builder() .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager)tmf.getTrustManagers()[0])
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。