OkHttp怎么用

发布时间:2021-12-04 11:48:36 作者:小新
来源:亿速云 阅读:229
# 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'

Java项目(Maven)

<dependency>
  <groupId>com.squareup.okhttp3</groupId>
  <artifactId>okhttp</artifactId>
  <version>4.9.3</version>
</dependency>

2.2 创建OkHttpClient实例

OkHttpClient client = new OkHttpClient();

2.3 发送简单GET请求

// 创建请求
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);
    }
}

2.4 配置超时时间

OkHttpClient client = new OkHttpClient.Builder()
    .connectTimeout(10, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .writeTimeout(30, TimeUnit.SECONDS)
    .build();

3. 同步与异步请求

3.1 同步请求

同步请求会阻塞当前线程直到收到响应:

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());
}

3.2 异步请求

异步请求不会阻塞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());
        }
    }
});

3.3 同步与异步的选择

4. 请求与响应详解

4.1 构建复杂请求

添加请求头

Request request = new Request.Builder()
    .url("https://api.example.com/data")
    .header("User-Agent", "OkHttp Example")
    .addHeader("Accept", "application/json")
    .build();

POST请求与请求体

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();

4.2 处理响应

响应头处理

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();

4.3 表单提交

application/x-www-form-urlencoded

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();

multipart/form-data

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();

5. 拦截器与自定义功能

5.1 拦截器基础

拦截器可以监控、重写和重试请求:

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;
    }
}

5.2 添加拦截器

OkHttpClient client = new OkHttpClient.Builder()
    .addInterceptor(new LoggingInterceptor())
    .build();

5.3 网络拦截器

网络拦截器可以访问更多请求信息,如Connection:

class NetworkLoggingInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        // 实现类似LoggingInterceptor但可以访问更多网络层信息
    }
}

OkHttpClient client = new OkHttpClient.Builder()
    .addNetworkInterceptor(new NetworkLoggingInterceptor())
    .build();

5.4 自定义拦截器应用场景

  1. 日志记录:记录请求和响应信息
  2. 认证:自动添加认证头
  3. 重试机制:在特定条件下自动重试请求
  4. 缓存控制:自定义缓存策略
  5. 请求/响应修改:统一修改请求或响应

6. 文件上传与下载

6.1 文件上传

上传单个文件

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);
});

6.2 文件下载

基本下载

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();

7. WebSocket通信

7.1 WebSocket基础

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);

7.2 WebSocket消息类型

// 发送文本消息
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) {
    // 处理二进制消息
}

7.3 WebSocket关闭

// 正常关闭
webSocket.close(1000, "Goodbye!");

// 强制关闭
webSocket.cancel();

8. 连接池与性能优化

8.1 连接池配置

ConnectionPool connectionPool = new ConnectionPool(
    5, // 最大空闲连接数
    5, // 保持时间(分钟)
    TimeUnit.MINUTES);

OkHttpClient client = new OkHttpClient.Builder()
    .connectionPool(connectionPool)
    .build();

8.2 缓存配置

int cacheSize = 10 * 1024 * 1024; // 10MB
Cache cache = new Cache(new File("cacheDir"), cacheSize);

OkHttpClient client = new OkHttpClient.Builder()
    .cache(cache)
    .build();

8.3 DNS优化

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();

8.4 其他优化建议

  1. 复用OkHttpClient实例:避免为每个请求创建新实例
  2. 合理设置超时时间:根据网络状况调整
  3. 启用响应压缩:减少传输数据量
  4. 使用HTTP/2:提高连接效率
  5. 监控连接状态:及时发现并解决问题

9. HTTPS与安全配置

9.1 基本HTTPS支持

OkHttp默认支持HTTPS,无需额外配置:

Request request = new Request.Builder()
    .url("https://example.com")
    .build();

9.2 自定义证书验证

信任所有证书(仅用于测试环境)

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])

推荐阅读:
  1. Android OkHttp, 一行代码 OkHttp提升请求稳定性
  2. OkHttp解析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

okhttp

上一篇:mysql​升级过程中的mysql Cannot add foreign key constraint错误怎么解决

下一篇:如何使用Prometheus监控MySQL与MariaDB.md

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》