Apache httpclient & okhttp(2)

打印 上一主题 下一主题

主题 1571|帖子 1571|积分 4713

学习链接

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。
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5.     <modelVersion>4.0.0</modelVersion>
  6.     <groupId>com.zzhua</groupId>
  7.     <artifactId>demo-okhttp</artifactId>
  8.     <version>1.0-SNAPSHOT</version>
  9.     <properties>
  10.         <maven.compiler.source>8</maven.compiler.source>
  11.         <maven.compiler.target>8</maven.compiler.target>
  12.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  13.         <!--<okhttp.version>3.9.0</okhttp.version>-->
  14.         <!--<okhttp.version>3.14.9</okhttp.version>-->
  15.         <!-- OkHttp从4.x版本开始转向Kotlin, Kotlin 代码可以被编译成标准的 JVM 字节码运行,这与 Java 代码的最终执行形式完全兼容。 -->
  16.         <okhttp.version>4.12.0</okhttp.version>
  17.     </properties>
  18.     <dependencies>
  19.         <dependency>
  20.             <groupId>com.squareup.okhttp3</groupId>
  21.             <artifactId>okhttp</artifactId>
  22.             <version>${okhttp.version}</version>
  23.         </dependency>
  24.     </dependencies>
  25. </project>
复制代码
get请求

  1. import okhttp3.OkHttpClient;
  2. import okhttp3.Request;
  3. import okhttp3.Response;
  4. import java.io.IOException;
  5. public class Test01 {
  6.     public static void main(String[] args) {
  7.         OkHttpClient client = new OkHttpClient();
  8.         Request request = new Request.Builder()
  9.                 .url("http://www.baidu.com")
  10.                 .build();
  11.         try (Response response = client.newCall(request).execute()) {
  12.             System.out.println(response.body().string());
  13.         } catch (IOException e) {
  14.             throw new RuntimeException(e);
  15.         }
  16.     }
  17. }
复制代码
Post请求

  1. import okhttp3.*;
  2. public class Test02 {
  3.     public static void main(String[] args) {
  4.    
  5.         OkHttpClient client = new OkHttpClient();
  6.         RequestBody body = RequestBody.create(MediaType.parse("application/json"),
  7.                                                                                  "{"username":"zzhua"}");
  8.         Request request = new Request.Builder()
  9.                 .url("http://localhost:8080/ok01")
  10.                 .post(body)
  11.                 .build();
  12.         try (Response response = client.newCall(request).execute()) {
  13.             System.out.println(response.body().string());
  14.         } catch (Exception e) {
  15.             throw new RuntimeException(e);
  16.         }
  17.     }
  18. }
复制代码
示例代码

这些示例代码来自:https://square.github.io/okhttp/recipes,
官方也有对应的代码:https://github.com/square/okhttp/blob/okhttp_3.14.x/samples


同步请求

下载文件,打印headers,并将其响应正文打印为字符串。


  • 响应正文上的string()方法对于小文档来说既方便又高效。但是假如响应正文很大(大于1 MiB),避免string(),因为它会将整个文档加载到内存中。在这种情况下,更推荐将正文作为流处理惩罚。
  1. import okhttp3.Headers;
  2. import okhttp3.OkHttpClient;
  3. import okhttp3.Request;
  4. import okhttp3.Response;
  5. import java.io.IOException;
  6. public class TestSynchronous {
  7.     private final static OkHttpClient client = new OkHttpClient();
  8.     public static void main(String[] args) {
  9.         Request request = new Request.Builder()
  10.                 .url("https://publicobject.com/helloworld.txt")
  11.                 .build();
  12.         try (Response response = client.newCall(request).execute()) {
  13.             if (!response.isSuccessful())
  14.                 throw new IOException("Unexpected code " + response);
  15.                         // 获取响应头
  16.             Headers responseHeaders = response.headers();
  17.             for (int i = 0; i < responseHeaders.size(); i++) {
  18.                 System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
  19.             }
  20.                        
  21.                         // 获取响应体
  22.             System.out.println(response.body().string());
  23.         } catch (IOException e) {
  24.             throw new RuntimeException(e);
  25.         }
  26.     }
  27. }
复制代码
异步请求

在工作线程中下载文件,并在响应可读取时触发回调。该回调会在响应头准备停当后触发,但读取响应体仍大概壅闭线程。当前OkHttp未提供异步API以分块吸收响应体内容。
  1. @Slf4j
  2. public class Test02Async {
  3.     public static void main(String[] args) {
  4.         log.info("main start");
  5.         OkHttpClient okHttpClient = new OkHttpClient();
  6.         Request requeset = new Request.Builder()
  7.                 .url("http://publicobject.com/helloworld.txt")
  8.                 .build();
  9.         Call call = okHttpClient.newCall(requeset);
  10.         log.info("call.enqueue");
  11.         // 执行回调的线程不是main线程
  12.         call.enqueue(new Callback() {
  13.             @Override
  14.             public void onFailure(Call call, IOException e) {
  15.                 log.info("=========请求失败=========: {}", e);
  16.             }
  17.             @Override
  18.             public void onResponse(Call call, Response response) throws IOException {
  19.                 log.info("=========获得响应=========");
  20.                 try (ResponseBody responseBody = response.body()) {
  21.                     if (!response.isSuccessful())
  22.                         throw new IOException("Unexpected code " + response);
  23.                     Headers responseHeaders = response.headers();
  24.                     for (int i = 0, size = responseHeaders.size(); i < size; i++) {
  25.                         System.out.println(responseHeaders.name(i) + ": " + responseHeaders.value(i));
  26.                     }
  27.                     System.out.println(responseBody.string());
  28.                 }
  29.             }
  30.         });
  31.         log.info("main end");
  32.     }
  33. }
复制代码
请求头&响应头

  1. public class TestHeader {
  2.     public static void main(String[] args) {
  3.         OkHttpClient okHttpClient = new OkHttpClient();
  4.         Request request = new Request.Builder()
  5.                 .url("https://api.github.com/repos/square/okhttp/issues")
  6.                 // 单个header值
  7.                 .header("User-Agent", "OkHttp Headers.java")
  8.                 // 多个header值
  9.                 .addHeader("Accept", "application/json; q=0.5")
  10.                 .addHeader("Accept", "application/vnd.github.v3+json")
  11.                 .build();
  12.         try (Response response = okHttpClient.newCall(request).execute()) {
  13.             if (!response.isSuccessful())
  14.                 throw new IOException("Unexpected code " + response);
  15.             System.out.println("Server: " + response.header("Server"));
  16.             System.out.println("Date: " + response.header("Date"));
  17.             // 多个响应头使用headers()获取
  18.             System.out.println("Vary: " + response.headers("Vary"));
  19.         } catch (IOException e) {
  20.             throw new RuntimeException(e);
  21.         }
  22.     }
  23. }
复制代码
post + 请求体

使用HTTP POST向服务发送请求正文。此示例将markdown文档发布到将markdown渲染为html。由于整个请求正文同时在内存中,因此避免使用此API发布大型(大于1 MiB)文档。
  1. public class TestRequestBody {
  2.     public static void main(String[] args) {
  3.         MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");
  4.         OkHttpClient client = new OkHttpClient();
  5.         String postBody = ""
  6.                 + "Releases\n"
  7.                 + "--------\n"
  8.                 + "\n"
  9.                 + " * _1.0_ May 6, 2013\n"
  10.                 + " * _1.1_ June 15, 2013\n"
  11.                 + " * _1.2_ August 11, 2013\n";
  12.         Request request = new Request.Builder()
  13.                 .url("https://api.github.com/markdown/raw")
  14.                 .post(RequestBody.create(mediaType, postBody))
  15.                 .build();
  16.         try {
  17.             Response response = client.newCall(request).execute();
  18.             if (!response.isSuccessful())
  19.                 throw new IOException("Unexpected code " + response);
  20.             System.out.println(response.body().string());
  21.         } catch (Exception e) {
  22.             throw new RuntimeException(e);
  23.         }
  24.     }
  25. }
复制代码
流式传输

我们在这里将请求体以流的情势举行POST提交。该请求体的内容在写入过程中动态生成。此示例直接将数据流式写入Okio的缓冲池(Buffered Sink)。您的程序大概更倾向于使用OutputStream,您可以通过BufferedSink.outputStream()方法获取它。


  • 流式传输(Streaming):区别于一次性加载完整数据到内存,流式传输答应边生成数据边发送,尤其得当:大文件传输(如视频上传)、及时生成数据(如传感器数据流)、内存敏感场景(避免OOM)
  1. public class Test05Stream {
  2.     public static void main(String[] args) {
  3.         MediaType MEDIA_TYPE_MARKDOWN = MediaType.parse("text/x-markdown; charset=utf-8");
  4.         OkHttpClient client = new OkHttpClient();
  5.         RequestBody requestBody = new RequestBody() {
  6.             @Override public MediaType contentType() {
  7.                 return MEDIA_TYPE_MARKDOWN;
  8.             }
  9.             @Override public void writeTo(BufferedSink sink) throws IOException {
  10.                 sink.writeUtf8("Numbers\n");
  11.                 sink.writeUtf8("-------\n");
  12.                 for (int i = 2; i <= 997; i++) {
  13.                     sink.writeUtf8(String.format(" * %s = %s\n", i, factor(i)));
  14.                 }
  15.             }
  16.             private String factor(int n) {
  17.                 for (int i = 2; i < n; i++) {
  18.                     int x = n / i;
  19.                     if (x * i == n) return factor(x) + " × " + i;
  20.                 }
  21.                 return Integer.toString(n);
  22.             }
  23.         };
  24.         Request request = new Request.Builder()
  25.                 .url("https://api.github.com/markdown/raw")
  26.                 .post(requestBody)
  27.                 .build();
  28.         try (Response response = client.newCall(request).execute()) {
  29.             if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
  30.             System.out.println(response.body().string());
  31.         } catch (IOException e) {
  32.             throw new RuntimeException(e);
  33.         }
  34.     }
  35. }
复制代码
流式传输扩展示例

通过观察客户端和服务端的日记,可以看到客户端发的同时,服务端也在收。
Test05StreamClient

  1. @Slf4j
  2. public class Test05StreamClient {
  3.     public static void main(String[] args) {
  4.         OkHttpClient client = new OkHttpClient.Builder()
  5.                 .writeTimeout(30, TimeUnit.SECONDS) // 延长写入超时
  6.                 .build();
  7.         // 创建流式 RequestBody
  8.         RequestBody requestBody = new RequestBody() {
  9.             @Override
  10.             public MediaType contentType() {
  11.                 return MediaType.parse("application/octet-stream");
  12.             }
  13.             @Override
  14.             public void writeTo(BufferedSink sink) throws IOException {
  15.                 try (java.io.OutputStream os = sink.outputStream()) {
  16.                     for (int i = 0; i < 50; i++) {
  17.                         // 模拟生成数据块
  18.                         String chunk = "Chunk-" + i + "\n";
  19.                         log.info("发送数据块: {}", chunk);
  20.                         os.write(chunk.getBytes());
  21.                         os.flush(); // 立即刷新缓冲区
  22.                         Thread.sleep(100); // 模拟延迟
  23.                     }
  24.                 } catch (InterruptedException e) {
  25.                     Thread.currentThread().interrupt();
  26.                 }
  27.             }
  28.         };
  29.         Request request = new Request.Builder()
  30.                 .url("http://localhost:8080/stream-upload-raw")
  31.                 .post(requestBody)
  32.                 .header("Content-Type", "application/octet-stream") // 强制覆盖
  33.                 .build();
  34.         // 异步执行
  35.         client.newCall(request).enqueue(new Callback() {
  36.             @Override
  37.             public void onFailure(Call call, IOException e) {
  38.                 log.info("[请求失败]");
  39.             }
  40.             @Override
  41.             public void onResponse(Call call, Response response) throws IOException {
  42.                 log.info("[请求成功]");
  43.                 System.out.println("上传成功: " + response.code());
  44.                 System.out.println("响应内容: " + response.body().string());
  45.                 response.close();
  46.             }
  47.         });
  48.     }
  49. }
复制代码
StreamController

  1. @Slf4j
  2. @RestController
  3. public class StreamController {
  4.     // 通过 HttpServletRequest 获取原始流
  5.     @PostMapping("/stream-upload-raw")
  6.     public String handleRawStream(HttpServletRequest request) {
  7.         try (InputStream rawStream = request.getInputStream()) {
  8.             byte[] buffer = new byte[1024];
  9.             int bytesRead;
  10.             while ((bytesRead = rawStream.read(buffer)) != -1) { // 按字节读取
  11.                 String chunk = new String(buffer, 0, bytesRead);
  12.                 log.info("[字节流] {}, {}", chunk.trim(), bytesRead);
  13.             }
  14.             return "Raw stream processed";
  15.         } catch (IOException e) {
  16.             return "Error: " + e.getMessage();
  17.         }
  18.     }
  19. }
复制代码
文件传输

将文件作为请求体。
  1. public class Test06File {
  2.     public static void main(String[] args) {
  3.         OkHttpClient client = new OkHttpClient();
  4.         Request request = new Request.Builder()
  5.                 .url("http://localhost:8080/okFile")
  6.                 .post(RequestBody.create(null, new File("C:\\Users\\zzhua195\\Desktop\\test.png")))
  7.                 .build();
  8.         try (Response response = client.newCall(request).execute()) {
  9.             if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
  10.             System.out.println(response.body().string());
  11.         } catch (IOException e) {
  12.             throw new RuntimeException(e);
  13.         }
  14.     }
  15. }
复制代码
后端代码
  1. @RequestMapping("okFile")
  2. public Object okFile(HttpServletRequest request) throws Exception {
  3.      ServletInputStream inputStream = request.getInputStream();
  4.      org.springframework.util.FileCopyUtils.copy(request.getInputStream(), new FileOutputStream("D:\\Projects\\practice\\demo-boot\\src\\main\\resources\\test.png"));
  5.      return "ok";
  6. }
复制代码
表单提交

使用FormBody.Builder构建一个像超文本标记语言<form>标签一样工作的请求正文。名称和值将使用超文本标记语言兼容的表单URL编码举行编码。
  1. public class Test07Form {
  2.     public static void main(String[] args) {
  3.         OkHttpClient client = new OkHttpClient();
  4.         RequestBody formBody = new FormBody.Builder()
  5.                 .add("username", "Jurassic Park")
  6.                 .build();
  7.         Request request = new Request.Builder()
  8.                 .url("http://localhost:8080/okForm")
  9.                 .post(formBody)
  10.                 .build();
  11.         try (Response response = client.newCall(request).execute()) {
  12.             if (!response.isSuccessful())
  13.                 throw new IOException("Unexpected code " + response);
  14.             System.out.println(response.body().string());
  15.         } catch (IOException e) {
  16.             throw new RuntimeException(e);
  17.         }
  18.     }
  19. }
复制代码
对应的后端代码
  1. @RequestMapping("okForm")
  2. public Object okForm(LoginForm loginForm) throws Exception {
  3.      log.info("[okForm] {}", loginForm);
  4.      return "ok";
  5. }
复制代码
文件上传

MultipartBody.Builder可以构建与超文本标记语言文件上传表单兼容的复杂请求正文。多部门请求正文的每个部门自己就是一个请求正文,而且可以界说自己的标头。假如存在,这些标头应该形貌部门正文,例如它的Content-Disposition。假如可用,Content-Length和Content-Type标头会主动添加
  1. public class Test08MultipartFile {
  2.     public static void main(String[] args) {
  3.         OkHttpClient client = new OkHttpClient();
  4.         RequestBody requestBody = new MultipartBody.Builder()
  5.                 .setType(MultipartBody.FORM)
  6.                 .addFormDataPart("comment", "Square Logo")
  7.                 .addFormDataPart("bin", "logo-square.png", RequestBody.create(null, new File("C:\\Users\\zzhua195\\Desktop\\test.png")))
  8.                 .build();
  9.         Request request = new Request.Builder()
  10.                 .header("Authorization", "Client-ID")
  11.                 .url("http://127.0.0.1:8080/multipart02")
  12.                 .post(requestBody)
  13.                 .build();
  14.         try (Response response = client.newCall(request).execute()) {
  15.             if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
  16.             System.out.println(response.body().string());
  17.         } catch (IOException e) {
  18.             throw new RuntimeException(e);
  19.         }
  20.     }
  21. }
复制代码
对应的后端代码
  1. @RequestMapping("multipart01")
  2. public Object multipart(
  3.          @RequestPart("bin") MultipartFile file,
  4.          @RequestPart("comment") String comment
  5. ) throws InterruptedException, IOException {
  6.      System.out.println(file.getBytes().length);
  7.      System.out.println(comment);
  8.      return "ojbk";
  9. }
  10. @RequestMapping("multipart02")
  11. public Object multipart(MultipartDTO multipartDTO) throws InterruptedException, IOException {
  12.      System.out.println(multipartDTO.getBin().getBytes().length);
  13.      System.out.println(multipartDTO.getComment());
  14.      return "ojbk";
  15. }
复制代码
响应缓存

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响应。
  1. import okhttp3.Cache;
  2. import okhttp3.OkHttpClient;
  3. import okhttp3.Request;
  4. import okhttp3.Response;
  5. import java.io.File;
  6. import java.io.IOException;
  7. public class Test09CacheResponse {
  8.     public static void main(String[] args) {
  9.         try {
  10.             Test09CacheResponse test = new Test09CacheResponse(new File("cache"));
  11.             test.run();
  12.         } catch (Exception e) {
  13.             throw new RuntimeException(e);
  14.         }
  15.     }
  16.     private final OkHttpClient client;
  17.     public Test09CacheResponse(File cacheDirectory) throws Exception {
  18.         int cacheSize = 10 * 1024 * 1024; // 10 MiB
  19.         Cache cache = new Cache(cacheDirectory, cacheSize);
  20.         client = new OkHttpClient.Builder()
  21.                 .cache(cache)
  22.                 .build();
  23.     }
  24.     public void run() throws Exception {
  25.         Request request = new Request.Builder()
  26.                 .url("http://publicobject.com/helloworld.txt")
  27.                 .build();
  28.         String response1Body;
  29.         try (Response response1 = client.newCall(request).execute()) {
  30.             if (!response1.isSuccessful()) throw new IOException("Unexpected code " + response1);
  31.             response1Body = response1.body().string();
  32.             System.out.println("Response 1 response:          " + response1);
  33.             System.out.println("Response 1 cache response:    " + response1.cacheResponse());
  34.             System.out.println("Response 1 network response:  " + response1.networkResponse());
  35.         }
  36.         String response2Body;
  37.         try (Response response2 = client.newCall(request).execute()) {
  38.             if (!response2.isSuccessful()) throw new IOException("Unexpected code " + response2);
  39.             response2Body = response2.body().string();
  40.             System.out.println("Response 2 response:          " + response2);
  41.             System.out.println("Response 2 cache response:    " + response2.cacheResponse());
  42.             System.out.println("Response 2 network response:  " + response2.networkResponse());
  43.         }
  44.         System.out.println("Response 2 equals Response 1? " + response1Body.equals(response2Body));
  45.     }
  46. }
  47. /*
  48. Response 1 response:          Response{protocol=http/1.1, code=200, message=OK, url=https://publicobject.com/helloworld.txt}
  49. Response 1 cache response:    null
  50. Response 1 network response:  Response{protocol=http/1.1, code=200, message=OK, url=https://publicobject.com/helloworld.txt}
  51. Response 2 response:          Response{protocol=http/1.1, code=200, message=OK, url=https://publicobject.com/helloworld.txt}
  52. Response 2 cache response:    Response{protocol=http/1.1, code=200, message=OK, url=https://publicobject.com/helloworld.txt}
  53. Response 2 network response:  null
  54. Response 2 equals Response 1? true
  55. */
复制代码
取消调用

使用Call.cancel()立即制止正在举行的调用。假如线程当前正在写入请求或读取响应,它将收到IOException。当不再必要调用时,使用它来节省网络;例如,当您的用户导航脱离应用程序时。同步和异步调用都可以取消。
  1. public class Test09CancelCall {
  2.     public static void main(String[] args) throws Exception {
  3.         new Test09CancelCall().run();
  4.     }
  5.     private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
  6.     private final OkHttpClient client = new OkHttpClient();
  7.     public void run() throws Exception {
  8.         Request request = new Request.Builder()
  9.                 .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay.
  10.                 .build();
  11.         final long startNanos = System.nanoTime();
  12.         final Call call = client.newCall(request);
  13.         // Schedule a job to cancel the call in 1 second.
  14.         executor.schedule(new Runnable() {
  15.             @Override public void run() {
  16.                 System.out.printf("%.2f Canceling call.%n", (System.nanoTime() - startNanos) / 1e9f);
  17.                 call.cancel();
  18.                 System.out.printf("%.2f Canceled call.%n", (System.nanoTime() - startNanos) / 1e9f);
  19.             }
  20.         }, 1, TimeUnit.SECONDS);
  21.         System.out.printf("%.2f Executing call.%n", (System.nanoTime() - startNanos) / 1e9f);
  22.         try (Response response = call.execute()) {
  23.             System.out.printf("%.2f Call was expected to fail, but completed: %s%n",  (System.nanoTime() - startNanos) / 1e9f, response);
  24.         } catch (IOException e) {
  25.             System.out.printf("%.2f Call failed as expected: %s%n", (System.nanoTime() - startNanos) / 1e9f, e);
  26.         }
  27.     }
  28. }
复制代码
超时

  1. private final OkHttpClient client;
  2. public ConfigureTimeouts() throws Exception {
  3.   client = new OkHttpClient.Builder()
  4.       .connectTimeout(10, TimeUnit.SECONDS)
  5.       .writeTimeout(10, TimeUnit.SECONDS)
  6.       .readTimeout(30, TimeUnit.SECONDS)
  7.       .build();
  8. }
  9. public void run() throws Exception {
  10.   Request request = new Request.Builder()
  11.       .url("http://httpbin.org/delay/2") // This URL is served with a 2 second delay.
  12.       .build();
  13.   try (Response response = client.newCall(request).execute()) {
  14.     System.out.println("Response completed: " + response);
  15.   }
  16. }
复制代码
每次调用配置

全部HTTP客户端配置都存在OkHttpClient中,包括署理设置、超时和缓存。当您必要更改单个调用的配置时,调用OkHttpClient.newBuilder()。这将返回一个与原始客户端共享相同连接池、调度程序和配置的构建器。在下面的示例中,我们发出一个超时500毫秒的请求,另一个超时3000毫秒。
  1. private final OkHttpClient client = new OkHttpClient();
  2. public void run() throws Exception {
  3.   Request request = new Request.Builder()
  4.       .url("http://httpbin.org/delay/1") // This URL is served with a 1 second delay.
  5.       .build();
  6.   // 拷贝client的属性,并作出自定义修改
  7.   OkHttpClient client1 = client.newBuilder()
  8.       .readTimeout(500, TimeUnit.MILLISECONDS)
  9.       .build();
  10.   try (Response response = client1.newCall(request).execute()) {
  11.     System.out.println("Response 1 succeeded: " + response);
  12.   } catch (IOException e) {
  13.     System.out.println("Response 1 failed: " + e);
  14.   }
  15.   // Copy to customize OkHttp for this request.
  16.   OkHttpClient client2 = client.newBuilder()
  17.       .readTimeout(3000, TimeUnit.MILLISECONDS)
  18.       .build();
  19.   try (Response response = client2.newCall(request).execute()) {
  20.     System.out.println("Response 2 succeeded: " + response);
  21.   } catch (IOException e) {
  22.     System.out.println("Response 2 failed: " + e);
  23.   }
  24. }
复制代码
处理惩罚鉴权

OkHttp可以主动重试未经身份验证的请求。当响应为401 Not Authorized时,会要求Authenticator提供凭据。实现应该构建一个包含缺失凭据的新请求。假如没有可用的凭据,则返回null以跳过重试。
  1. private final OkHttpClient client;
  2. public Authenticate() {
  3. client = new OkHttpClient.Builder()
  4.      .authenticator(new Authenticator() {
  5.        @Override public Request authenticate(Route route, Response response) throws IOException {
  6.          if (response.request().header("Authorization") != null) {
  7.            return null; // Give up, we've already attempted to authenticate.
  8.          }
  9.          System.out.println("Authenticating for response: " + response);
  10.          System.out.println("Challenges: " + response.challenges());
  11.          String credential = Credentials.basic("jesse", "password1");
  12.          return response.request().newBuilder()
  13.              .header("Authorization", credential)
  14.              .build();
  15.        }
  16.      })
  17.      .build();
  18. }
  19. public void run() throws Exception {
  20. Request request = new Request.Builder()
  21.      .url("http://publicobject.com/secrets/hellosecret.txt")
  22.      .build();
  23. try (Response response = client.newCall(request).execute()) {
  24.    if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
  25.    System.out.println(response.body().string());
  26. }
  27. }
复制代码
为避免在鉴权不起作用时举行多次重试,您可以返回null以放弃。例如,当已经实行了这些确切的凭据时,您大概希望跳过重试:
  1. if (credential.equals(response.request().header("Authorization"))) {
  2.         return null; // If we already failed with these credentials, don't retry.
  3. }
复制代码
当您达到应用程序界说的实行限定时,您也可以跳过重试:
  1. if (responseCount(response) >= 3) {
  2. return null; // If we've failed 3 times, give up.
  3. }
复制代码
拦截器

参考:https://square.github.io/okhttp/features/interceptors/

  1. import okhttp3.Interceptor;
  2. import okhttp3.OkHttpClient;
  3. import okhttp3.Request;
  4. import okhttp3.Response;
  5. import java.io.IOException;
  6. @Slf4j
  7. public class TestInterceptor {
  8.     public static void main(String[] args) throws IOException {
  9.         OkHttpClient client = new OkHttpClient.Builder()
  10.                 .addInterceptor(new LoggingInterceptor())
  11.                 // .addNetworkInterceptor(new LoggingInterceptor())
  12.                 .build();
  13.         Request request = new Request.Builder()
  14.                 .url("http://www.publicobject.com/helloworld.txt")
  15.                 .header("User-Agent", "OkHttp Example")
  16.                 .build();
  17.         Response response = client.newCall(request).execute();
  18.         response.body().close();
  19.     }
  20.     static class LoggingInterceptor implements Interceptor {
  21.         @Override public Response intercept(Interceptor.Chain chain) throws IOException {
  22.             Request request = chain.request();
  23.             long t1 = System.nanoTime();
  24.             log.info(String.format("Sending request %s on %s%n%s",
  25.                     request.url(), chain.connection(), request.headers()));
  26.             Response response = chain.proceed(request);
  27.             long t2 = System.nanoTime();
  28.             log.info(String.format("Received response for %s in %.1fms%n%s",
  29.                     response.request().url(), (t2 - t1) / 1e6d, response.headers()));
  30.             return response;
  31.         }
  32.     }
  33. }
复制代码
事件监听



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

海哥

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表