学习链接
Apache httpclient & okhttp(1)
Apache httpclient & okhttp(2)
okhttp github
okhttp官方使用文档
okhttp官方示例代码
OkHttp使用介绍
OkHttp使用进阶 译自OkHttp Github官方教程
SpringBoot 整合okHttp okhttp3用法
Java中常用的HTTP客户端库:OkHttp和HttpClient(包含请求示例代码)
深入浅出 OkHttp 源码解析及应用实践
okhttp
okhttp概述
HTTP是当代应用程序的网络方式。这是我们互换数据和媒体的方式。高效地使用HTTP可以让您的东西加载更快并节省带宽。
OkHttp使用起来很方便。它的请求/响应API筹划具有流式构建和不可变性。它支持同步壅闭调用和带有回调的异步调用。
特点
OkHttp是一个高效的默认HTTP客户端
- HTTP/2支持答应对同一主机的全部请求共享一个套接字。
- 连接池淘汰了请求延时(假如HTTP/2不可用)。
- 透明GZIP缩小了下载巨细。
- 响应缓存完全避免了重复请求的网络。
OkHttp遵照当代HTTP规范,例如
- HTTP语义-RFC 9110
- HTTP缓存-RFC 9111
- HTTP/1.1-RFC 9112
- HTTP/2-RFC 9113
- Websocket-RFC 6455
- SSE-服务器发送的事件
快速入门
pom.xml
注意:okhttp的3.9.0版本用的是java,okhttp4.12.0用的是kotlin。
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.zzhua</groupId>
- <artifactId>demo-okhttp</artifactId>
- <version>1.0-SNAPSHOT</version>
- <properties>
- <maven.compiler.source>8</maven.compiler.source>
- <maven.compiler.target>8</maven.compiler.target>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- <!--<okhttp.version>3.9.0</okhttp.version>-->
- <!--<okhttp.version>3.14.9</okhttp.version>-->
- <!-- OkHttp从4.x版本开始转向Kotlin, Kotlin 代码可以被编译成标准的 JVM 字节码运行,这与 Java 代码的最终执行形式完全兼容。 -->
- <okhttp.version>4.12.0</okhttp.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>com.squareup.okhttp3</groupId>
- <artifactId>okhttp</artifactId>
- <version>${okhttp.version}</version>
- </dependency>
- </dependencies>
- </project>
复制代码 get请求
- import okhttp3.OkHttpClient;
- import okhttp3.Request;
- import okhttp3.Response;
- import java.io.IOException;
- public class Test01 {
- public static void main(String[] args) {
- OkHttpClient client = new OkHttpClient();
- Request request = new Request.Builder()
- .url("http://www.baidu.com")
- .build();
- try (Response response = client.newCall(request).execute()) {
- System.out.println(response.body().string());
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
复制代码 Post请求
- import okhttp3.*;
- public class Test02 {
- public static void main(String[] args) {
-
- OkHttpClient client = new OkHttpClient();
- RequestBody body = RequestBody.create(MediaType.parse("application/json"),
- "{"username":"zzhua"}");
- Request request = new Request.Builder()
- .url("http://localhost:8080/ok01")
- .post(body)
- .build();
- try (Response response = client.newCall(request).execute()) {
- System.out.println(response.body().string());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- }
复制代码 示例代码
这些示例代码来自:https://square.github.io/okhttp/recipes,
官方也有对应的代码:https://github.com/square/okhttp/blob/okhttp_3.14.x/samples
同步请求
下载文件,打印headers,并将其响应正文打印为字符串。
- 响应正文上的string()方法对于小文档来说既方便又高效。但是假如响应正文很大(大于1 MiB),避免string(),因为它会将整个文档加载到内存中。在这种情况下,更推荐将正文作为流处理惩罚。
- import okhttp3.Headers;
- import okhttp3.OkHttpClient;
- import okhttp3.Request;
- import okhttp3.Response;
- import java.io.IOException;
- public class TestSynchronous {
- private final static OkHttpClient client = new OkHttpClient();
- public static void main(String[] args) {
- Request request = new Request.Builder()
- .url("https://publicobject.com/helloworld.txt")
- .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());
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
复制代码 异步请求
在工作线程中下载文件,并在响应可读取时触发回调。该回调会在响应头准备停当后触发,但读取响应体仍大概壅闭线程。当前OkHttp未提供异步API以分块吸收响应体内容。
- @Slf4j
- public class Test02Async {
- public static void main(String[] args) {
- log.info("main start");
- OkHttpClient okHttpClient = new OkHttpClient();
- Request requeset = new Request.Builder()
- .url("http://publicobject.com/helloworld.txt")
- .build();
- Call call = okHttpClient.newCall(requeset);
- log.info("call.enqueue");
- // 执行回调的线程不是main线程
- call.enqueue(new Callback() {
- @Override
- public void onFailure(Call call, IOException e) {
- log.info("=========请求失败=========: {}", e);
- }
- @Override
- public void onResponse(Call call, Response response) throws IOException {
- log.info("=========获得响应=========");
- try (ResponseBody responseBody = response.body()) {
- if (!response.isSuccessful())
- throw new IOException("Unexpected code " + response);
- Headers responseHeaders = response.headers();
- for (int i = 0, size = responseHeaders.size(); i < size; i++) {
- System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
- }
- System.out.println(responseBody.string());
- }
- }
- });
- log.info("main end");
- }
- }
复制代码 请求头&响应头
- public class TestHeader {
- public static void main(String[] args) {
- OkHttpClient okHttpClient = new OkHttpClient();
- Request request = new Request.Builder()
- .url("https://api.github.com/repos/square/okhttp/issues")
- // 单个header值
- .header("User-Agent", "OkHttp Headers.java")
- // 多个header值
- .addHeader("Accept", "application/json; q=0.5")
- .addHeader("Accept", "application/vnd.github.v3+json")
- .build();
- try (Response response = okHttpClient.newCall(request).execute()) {
- if (!response.isSuccessful())
- throw new IOException("Unexpected code " + response);
- System.out.println("Server: " + response.header("Server"));
- System.out.println("Date: " + response.header("Date"));
- // 多个响应头使用headers()获取
- System.out.println("Vary: " + response.headers("Vary"));
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
复制代码 post + 请求体
使用HTTP POST向服务发送请求正文。此示例将markdown文档发布到将markdown渲染为html。由于整个请求正文同时在内存中,因此避免使用此API发布大型(大于1 MiB)文档。
- public class TestRequestBody {
- public static void main(String[] args) {
- MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
- OkHttpClient client = new OkHttpClient();
- String postBody = ""
- + "Releases\n"
- + "--------\n"
- + "\n"
- + " * _1.0_ May 6, 2013\n"
- + " * _1.1_ June 15, 2013\n"
- + " * _1.2_ August 11, 2013\n";
- Request request = new Request.Builder()
- .url("https://api.github.com/markdown/raw")
- .post(RequestBody.create(mediaType, postBody))
- .build();
- try {
- Response response = client.newCall(request).execute();
- if (!response.isSuccessful())
- throw new IOException("Unexpected code " + response);
- System.out.println(response.body().string());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- }
复制代码 流式传输
我们在这里将请求体以流的情势举行POST提交。该请求体的内容在写入过程中动态生成。此示例直接将数据流式写入Okio的缓冲池(Buffered Sink)。您的程序大概更倾向于使用OutputStream,您可以通过BufferedSink.outputStream()方法获取它。
- 流式传输(Streaming):区别于一次性加载完整数据到内存,流式传输答应边生成数据边发送,尤其得当:大文件传输(如视频上传)、及时生成数据(如传感器数据流)、内存敏感场景(避免OOM)
- public class Test05Stream {
- public static void main(String[] args) {
- MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
- OkHttpClient client = new OkHttpClient();
- RequestBody requestBody = new RequestBody() {
- @Override public MediaType contentType() {
- return MEDIA_TYPE_MARKDOWN;
- }
- @Override public void writeTo(BufferedSink sink) throws IOException {
- sink.writeUtf8("Numbers\n");
- sink.writeUtf8("-------\n");
- for (int i = 2; i <= 997; i++) {
- sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i)));
- }
- }
- private String factor(int n) {
- for (int i = 2; i < n; i++) {
- int x = n / i;
- if (x * i == n) return factor(x) + " × " + i;
- }
- return Integer.toString(n);
- }
- };
- Request request = new Request.Builder()
- .url("https://api.github.com/markdown/raw")
- .post(requestBody)
- .build();
- try (Response response = client.newCall(request).execute()) {
- if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
- System.out.println(response.body().string());
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
复制代码 流式传输扩展示例
通过观察客户端和服务端的日记,可以看到客户端发的同时,服务端也在收。
Test05StreamClient
- @Slf4j
- public class Test05StreamClient {
- public static void main(String[] args) {
- OkHttpClient client = new OkHttpClient.Builder()
- .writeTimeout(30, TimeUnit.SECONDS) // 延长写入超时
- .build();
- // 创建流式 RequestBody
- RequestBody requestBody = new RequestBody() {
- @Override
- public MediaType contentType() {
- return MediaType.parse("application/octet-stream");
- }
- @Override
- public void writeTo(BufferedSink sink) throws IOException {
- try (java.io.OutputStream os = sink.outputStream()) {
- for (int i = 0; i < 50; i++) {
- // 模拟生成数据块
- String chunk = "Chunk-" + i + "\n";
- log.info("发送数据块: {}", chunk);
- os.write(chunk.getBytes());
- os.flush(); // 立即刷新缓冲区
- Thread.sleep(100); // 模拟延迟
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- };
- Request request = new Request.Builder()
- .url("http://localhost:8080/stream-upload-raw")
- .post(requestBody)
- .header("Content-Type", "application/octet-stream") // 强制覆盖
- .build();
- // 异步执行
- client.newCall(request).enqueue(new Callback() {
- @Override
- public void onFailure(Call call, IOException e) {
- log.info("[请求失败]");
- }
- @Override
- public void onResponse(Call call, Response response) throws IOException {
- log.info("[请求成功]");
- System.out.println("上传成功: " + response.code());
- System.out.println("响应内容: " + response.body().string());
- response.close();
- }
- });
- }
- }
复制代码 StreamController
- @Slf4j
- @RestController
- public class StreamController {
- // 通过 HttpServletRequest 获取原始流
- @PostMapping("/stream-upload-raw")
- public String handleRawStream(HttpServletRequest request) {
- try (InputStream rawStream = request.getInputStream()) {
- byte[] buffer = new byte[1024];
- int bytesRead;
- while ((bytesRead = rawStream.read(buffer)) != -1) { // 按字节读取
- String chunk = new String(buffer, 0, bytesRead);
- log.info("[字节流] {}, {}", chunk.trim(), bytesRead);
- }
- return "Raw stream processed";
- } catch (IOException e) {
- return "Error: " + e.getMessage();
- }
- }
- }
复制代码 文件传输
将文件作为请求体。
- public class Test06File {
- public static void main(String[] args) {
- OkHttpClient client = new OkHttpClient();
- Request request = new Request.Builder()
- .url("http://localhost:8080/okFile")
- .post(RequestBody.create(null, new File("C:\\Users\\zzhua195\\Desktop\\test.png")))
- .build();
- try (Response response = client.newCall(request).execute()) {
- if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
- System.out.println(response.body().string());
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
复制代码 后端代码
- @RequestMapping("okFile")
- public Object okFile(HttpServletRequest request) throws Exception {
- ServletInputStream inputStream = request.getInputStream();
- org.springframework.util.FileCopyUtils.copy(request.getInputStream(), new FileOutputStream("D:\\Projects\\practice\\demo-boot\\src\\main\\resources\\test.png"));
- return "ok";
- }
复制代码 表单提交
使用FormBody.Builder构建一个像超文本标记语言<form>标签一样工作的请求正文。名称和值将使用超文本标记语言兼容的表单URL编码举行编码。
- public class Test07Form {
- public static void main(String[] args) {
- OkHttpClient client = new OkHttpClient();
- RequestBody formBody = new FormBody.Builder()
- .add("username", "Jurassic Park")
- .build();
- Request request = new Request.Builder()
- .url("http://localhost:8080/okForm")
- .post(formBody)
- .build();
- try (Response response = client.newCall(request).execute()) {
- if (!response.isSuccessful())
- throw new IOException("Unexpected code " + response);
- System.out.println(response.body().string());
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
复制代码 对应的后端代码
- @RequestMapping("okForm")
- public Object okForm(LoginForm loginForm) throws Exception {
- log.info("[okForm] {}", loginForm);
- return "ok";
- }
复制代码 文件上传
MultipartBody.Builder可以构建与超文本标记语言文件上传表单兼容的复杂请求正文。多部门请求正文的每个部门自己就是一个请求正文,而且可以界说自己的标头。假如存在,这些标头应该形貌部门正文,例如它的Content-Disposition。假如可用,Content-Length和Content-Type标头会主动添加
- public class Test08MultipartFile {
- public static void main(String[] args) {
- OkHttpClient client = new OkHttpClient();
- RequestBody requestBody = new MultipartBody.Builder()
- .setType(MultipartBody.FORM)
- .addFormDataPart("comment", "Square Logo")
- .addFormDataPart("bin", "logo-square.png", RequestBody.create(null, new File("C:\\Users\\zzhua195\\Desktop\\test.png")))
- .build();
- Request request = new Request.Builder()
- .header("Authorization", "Client-ID")
- .url("http://127.0.0.1:8080/multipart02")
- .post(requestBody)
- .build();
- try (Response response = client.newCall(request).execute()) {
- if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
- System.out.println(response.body().string());
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
复制代码 对应的后端代码
- @RequestMapping("multipart01")
- public Object multipart(
- @RequestPart("bin") MultipartFile file,
- @RequestPart("comment") String comment
- ) throws InterruptedException, IOException {
- System.out.println(file.getBytes().length);
- System.out.println(comment);
- return "ojbk";
- }
- @RequestMapping("multipart02")
- public Object multipart(MultipartDTO multipartDTO) throws InterruptedException, IOException {
- System.out.println(multipartDTO.getBin().getBytes().length);
- System.out.println(multipartDTO.getComment());
- return "ojbk";
- }
复制代码 响应缓存
1、要缓存响应,您必要一个可以读取和写入的缓存目录,以及对缓存巨细的限定。缓存目录应该是私有的,不受信托的应用程序应该无法读取其内容!
2、让多个缓存同时访问同一个缓存目录是错误的。大多数应用程序应该只调用一次new OkHttpClient(),用它们的缓存配置它,并在任何地方使用相同的实例。否则两个缓存实例会相互踩踏,粉碎响应缓存,并大概使您的程序瓦解。
3、响应缓存对全部配置都使用HTTP标头。您可以添加请求标头,如Cache-Control: max-stale=3600,OkHttp的缓存将恭敬它们。您的网络服务器使用自己的响应标头配置缓存响应的时间,如Cache-Control: max-age=9600。有缓存标头可以强制缓存响应、强制网络响应或强制使用条件GET验证网络响应。
4、要防止响应使用缓存,请使用CacheControl.FORCE_NETWORK。要防止它使用网络,请使用CacheControl.FORCE_CACHE。请注意:假如您使用FORCE_CACHE而且响应必要网络,OkHttp将返回504 Unsatisfiable Request响应。
- import okhttp3.Cache;
- import okhttp3.OkHttpClient;
- import okhttp3.Request;
- import okhttp3.Response;
- import java.io.File;
- import java.io.IOException;
- public class Test09CacheResponse {
- public static void main(String[] args) {
- try {
- Test09CacheResponse test = new Test09CacheResponse(new File("cache"));
- test.run();
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- private final OkHttpClient client;
- public Test09CacheResponse(File cacheDirectory) throws Exception {
- int cacheSize = 10 * 1024 * 1024; // 10 MiB
- Cache cache = new Cache(cacheDirectory, cacheSize);
- client = new OkHttpClient.Builder()
- .cache(cache)
- .build();
- }
- public void run() throws Exception {
- Request request = new Request.Builder()
- .url("http://publicobject.com/helloworld.txt")
- .build();
- String response1Body;
- try (Response response1 = client.newCall(request).execute()) {
- if (!response1.isSuccessful()) throw new IOException("Unexpected code " + response1);
- response1Body = response1.body().string();
- System.out.println("Response 1 response: " + response1);
- System.out.println("Response 1 cache response: " + response1.cacheResponse());
- System.out.println("Response 1 network response: " + response1.networkResponse());
- }
- String response2Body;
- try (Response response2 = client.newCall(request).execute()) {
- if (!response2.isSuccessful()) throw new IOException("Unexpected code " + response2);
- response2Body = response2.body().string();
- System.out.println("Response 2 response: " + response2);
- System.out.println("Response 2 cache response: " + response2.cacheResponse());
- System.out.println("Response 2 network response: " + response2.networkResponse());
- }
- System.out.println("Response 2 equals Response 1? " + response1Body.equals(response2Body));
- }
- }
- /*
- Response 1 response: Response{protocol=http/1.1, code=200, message=OK, url=https://publicobject.com/helloworld.txt}
- Response 1 cache response: null
- Response 1 network response: Response{protocol=http/1.1, code=200, message=OK, url=https://publicobject.com/helloworld.txt}
- Response 2 response: Response{protocol=http/1.1, code=200, message=OK, url=https://publicobject.com/helloworld.txt}
- Response 2 cache response: Response{protocol=http/1.1, code=200, message=OK, url=https://publicobject.com/helloworld.txt}
- Response 2 network response: null
- Response 2 equals Response 1? true
- */
复制代码 取消调用
使用Call.cancel()立即制止正在举行的调用。假如线程当前正在写入请求或读取响应,它将收到IOException。当不再必要调用时,使用它来节省网络;例如,当您的用户导航脱离应用程序时。同步和异步调用都可以取消。
- public class Test09CancelCall {
- public static void main(String[] args) throws Exception {
- new Test09CancelCall().run();
- }
- private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
- private final OkHttpClient client = new OkHttpClient();
- public void run() throws Exception {
- Request request = new Request.Builder()
- .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay.
- .build();
- final long startNanos = System.nanoTime();
- final Call call = client.newCall(request);
- // Schedule a job to cancel the call in 1 second.
- executor.schedule(new Runnable() {
- @Override public void run() {
- System.out.printf("%.2f Canceling call.%n", (System.nanoTime() - startNanos) / 1e9f);
- call.cancel();
- System.out.printf("%.2f Canceled call.%n", (System.nanoTime() - startNanos) / 1e9f);
- }
- }, 1, TimeUnit.SECONDS);
- System.out.printf("%.2f Executing call.%n", (System.nanoTime() - startNanos) / 1e9f);
- try (Response response = call.execute()) {
- System.out.printf("%.2f Call was expected to fail, but completed: %s%n", (System.nanoTime() - startNanos) / 1e9f, response);
- } catch (IOException e) {
- System.out.printf("%.2f Call failed as expected: %s%n", (System.nanoTime() - startNanos) / 1e9f, e);
- }
- }
- }
复制代码 超时
- private final OkHttpClient client;
- public ConfigureTimeouts() throws Exception {
- client = new OkHttpClient.Builder()
- .connectTimeout(10, TimeUnit.SECONDS)
- .writeTimeout(10, TimeUnit.SECONDS)
- .readTimeout(30, TimeUnit.SECONDS)
- .build();
- }
- public void run() throws Exception {
- Request request = new Request.Builder()
- .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay.
- .build();
- try (Response response = client.newCall(request).execute()) {
- System.out.println("Response completed: " + response);
- }
- }
复制代码 每次调用配置
全部HTTP客户端配置都存在OkHttpClient中,包括署理设置、超时和缓存。当您必要更改单个调用的配置时,调用OkHttpClient.newBuilder()。这将返回一个与原始客户端共享相同连接池、调度程序和配置的构建器。在下面的示例中,我们发出一个超时500毫秒的请求,另一个超时3000毫秒。
- private final OkHttpClient client = new OkHttpClient();
- public void run() throws Exception {
- Request request = new Request.Builder()
- .url("http://httpbin.org/delay/1") // This URL is served with a 1 second delay.
- .build();
- // 拷贝client的属性,并作出自定义修改
- OkHttpClient client1 = client.newBuilder()
- .readTimeout(500, TimeUnit.MILLISECONDS)
- .build();
- try (Response response = client1.newCall(request).execute()) {
- System.out.println("Response 1 succeeded: " + response);
- } catch (IOException e) {
- System.out.println("Response 1 failed: " + e);
- }
- // Copy to customize OkHttp for this request.
- OkHttpClient client2 = client.newBuilder()
- .readTimeout(3000, TimeUnit.MILLISECONDS)
- .build();
- try (Response response = client2.newCall(request).execute()) {
- System.out.println("Response 2 succeeded: " + response);
- } catch (IOException e) {
- System.out.println("Response 2 failed: " + e);
- }
- }
复制代码 处理惩罚鉴权
OkHttp可以主动重试未经身份验证的请求。当响应为401 Not Authorized时,会要求Authenticator提供凭据。实现应该构建一个包含缺失凭据的新请求。假如没有可用的凭据,则返回null以跳过重试。
- private final OkHttpClient client;
- public Authenticate() {
- client = new OkHttpClient.Builder()
- .authenticator(new Authenticator() {
- @Override public Request authenticate(Route route, Response response) throws IOException {
- if (response.request().header("Authorization") != null) {
- return null; // Give up, we've already attempted to authenticate.
- }
- System.out.println("Authenticating for response: " + response);
- System.out.println("Challenges: " + response.challenges());
- String credential = Credentials.basic("jesse", "password1");
- return response.request().newBuilder()
- .header("Authorization", credential)
- .build();
- }
- })
- .build();
- }
- public void run() throws Exception {
- Request request = new Request.Builder()
- .url("http://publicobject.com/secrets/hellosecret.txt")
- .build();
- try (Response response = client.newCall(request).execute()) {
- if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
- System.out.println(response.body().string());
- }
- }
复制代码 为避免在鉴权不起作用时举行多次重试,您可以返回null以放弃。例如,当已经实行了这些确切的凭据时,您大概希望跳过重试:
- if (credential.equals(response.request().header("Authorization"))) {
- return null; // If we already failed with these credentials, don't retry.
- }
复制代码 当您达到应用程序界说的实行限定时,您也可以跳过重试:
- if (responseCount(response) >= 3) {
- return null; // If we've failed 3 times, give up.
- }
复制代码 拦截器
参考:https://square.github.io/okhttp/features/interceptors/

- import okhttp3.Interceptor;
- import okhttp3.OkHttpClient;
- import okhttp3.Request;
- import okhttp3.Response;
- import java.io.IOException;
- @Slf4j
- public class TestInterceptor {
- public static void main(String[] args) throws IOException {
- OkHttpClient client = new OkHttpClient.Builder()
- .addInterceptor(new LoggingInterceptor())
- // .addNetworkInterceptor(new LoggingInterceptor())
- .build();
- Request request = new Request.Builder()
- .url("http://www.publicobject.com/helloworld.txt")
- .header("User-Agent", "OkHttp Example")
- .build();
- Response response = client.newCall(request).execute();
- response.body().close();
- }
- static class LoggingInterceptor implements Interceptor {
- @Override public Response intercept(Interceptor.Chain chain) throws IOException {
- Request request = chain.request();
- long t1 = System.nanoTime();
- log.info(String.format("Sending request %s on %s%n%s",
- request.url(), chain.connection(), request.headers()));
- Response response = chain.proceed(request);
- long t2 = System.nanoTime();
- log.info(String.format("Received response for %s in %.1fms%n%s",
- response.request().url(), (t2 - t1) / 1e6d, response.headers()));
- return response;
- }
- }
- }
复制代码 事件监听
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |