你知道的越多,不知道的就越多,业余的像一棵小草!

你来,我们一起精进!你不来,我和你的竞争对手一起精进!

编辑:业余草

来源:juejin.im/post/6844904040644476941

推荐:https://www.xttblog.com/?p=5097

写在前面

为什么会写这篇文章,起因于和朋友的聊天


这又触及到我的知识盲区了,首先来一波面向百度学习,直接根据关键字 httpclient 和 okhttp 的区别、性能比较进行搜索,没有找到想要的答案,于是就去 overstackflow 上看看是不是有人问过这个问题,果然不会让你失望的


所以从使用、性能、超时配置方面进行比较

使用

HttpClient 和 OkHttp 一般用于调用其它服务,一般服务暴露出来的接口都为 http,http 常用请求类型就为 GET、PUT、POST 和 DELETE,因此主要介绍这些请求类型的调用

HttpClient 使用介绍

使用 HttpClient 发送请求主要分为一下几步骤:

  • 创建 CloseableHttpClient 对象或 CloseableHttpAsyncClient 对象,前者同步,后者为异步
  • 创建 Http 请求对象
  • 调用 execute 方法执行请求,如果是异步请求在执行之前需调用 start 方法

创建连接:

CloseableHttpClient httpClient = HttpClientBuilder.create().build();

该连接为同步连接

GET 请求:

@Testpublic void testGet() throws IOException {    String api = "/api/files/1";    String url = String.format("%s%s", BASE\_URL, api);    HttpGet httpGet = new HttpGet(url);    CloseableHttpResponse response = httpClient.execute(httpGet);    System.out.println(EntityUtils.toString(response.getEntity()));}

使用 HttpGet 表示该连接为 GET 请求,HttpClient 调用 execute 方法发送 GET 请求

PUT 请求:

@Testpublic void testPut() throws IOException {    String api = "/api/user";    String url = String.format("%s%s", BASE\_URL, api);    HttpPut httpPut = new HttpPut(url);    UserVO userVO = UserVO.builder().name("h2t").id(16L).build();    httpPut.setHeader("Content-Type", "application/json;charset=utf8");    httpPut.setEntity(new StringEntity(JSONObject.toJSONString(userVO), "UTF-8"));    CloseableHttpResponse response = httpClient.execute(httpPut);    System.out.println(EntityUtils.toString(response.getEntity()));}

POST 请求:

  • 添加对象
@Testpublic void testPost() throws IOException { String api = "/api/user"; String url = String.format("%s%s", BASE\_URL, api); HttpPost httpPost = new HttpPost(url); UserVO userVO = UserVO.builder().name("h2t2").build(); httpPost.setHeader("Content-Type", "application/json;charset=utf8"); httpPost.setEntity(new StringEntity(JSONObject.toJSONString(userVO), "UTF-8")); CloseableHttpResponse response = httpClient.execute(httpPost); System.out.println(EntityUtils.toString(response.getEntity()));}

该请求是一个创建对象的请求,需要传入一个 json 字符串

  • 上传文件
@Testpublic void testUpload1() throws IOException { String api = "/api/files/1"; String url = String.format("%s%s", BASE\_URL, api); HttpPost httpPost = new HttpPost(url); File file = new File("C:/Users/hetiantian/Desktop/学习/docker\_practice.pdf"); FileBody fileBody = new FileBody(file); MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.setMode(HttpMultipartMode.BROWSER\_COMPATIBLE); builder.addPart("file", fileBody);  //addPart上传文件 HttpEntity entity = builder.build(); httpPost.setEntity(entity); CloseableHttpResponse response = httpClient.execute(httpPost); System.out.println(EntityUtils.toString(response.getEntity()));}

通过 addPart 上传文件

DELETE 请求:

@Testpublic void testDelete() throws IOException {    String api = "/api/user/12";    String url = String.format("%s%s", BASE\_URL, api);    HttpDelete httpDelete = new HttpDelete(url);    CloseableHttpResponse response = httpClient.execute(httpDelete);    System.out.println(EntityUtils.toString(response.getEntity()));}

请求的取消:

@Testpublic void testCancel() throws IOException {    String api = "/api/files/1";    String url = String.format("%s%s", BASE\_URL, api);    HttpGet httpGet = new HttpGet(url);    httpGet.setConfig(requestConfig);  //设置超时时间    //测试连接的取消

    long begin = System.currentTimeMillis();    CloseableHttpResponse response = httpClient.execute(httpGet);    while (true) {        if (System.currentTimeMillis() - begin > 1000) {          httpGet.abort();          System.out.println("task canceled");          break;      }    }

    System.out.println(EntityUtils.toString(response.getEntity()));}

调用 abort 方法取消请求 执行结果:

task canceledcost 8098 mscDisconnected from the target VM, address: '127.0.0.1:60549', transport: 'socket'

java.net.SocketException: socket closed...【省略】

OkHttp 使用

使用 OkHttp 发送请求主要分为一下几步骤:

  • 创建 OkHttpClient 对象
  • 创建 Request 对象
  • 将 Request 对象封装为 Call
  • 通过 Call 来执行同步或异步请求,调用 execute 方法同步执行,调用 enqueue 方法异步执行

创建连接:

private OkHttpClient client = new OkHttpClient();

GET 请求:

@Testpublic void testGet() throws IOException {    String api = "/api/files/1";    String url = String.format("%s%s", BASE\_URL, api);    Request request = new Request.Builder()            .url(url)            .get()            .build();    final Call call = client.newCall(request);    Response response = call.execute();    System.out.println(response.body().string());}

PUT 请求:

@Testpublic void testPut() throws IOException {    String api = "/api/user";    String url = String.format("%s%s", BASE\_URL, api);    //请求参数    UserVO userVO = UserVO.builder().name("h2t").id(11L).build();    RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),    JSONObject.toJSONString(userVO));    Request request = new Request.Builder()            .url(url)            .put(requestBody)            .build();    final Call call = client.newCall(request);    Response response = call.execute();    System.out.println(response.body().string());}

POST 请求:

  • 添加对象
@Testpublic void testPost() throws IOException { String api = "/api/user"; String url = String.format("%s%s", BASE\_URL, api); //请求参数 JSONObject json = new JSONObject(); json.put("name", "hetiantian"); RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),     String.valueOf(json)); Request request = new Request.Builder()   .url(url)   .post(requestBody) //post请求     .build(); final Call call = client.newCall(request); Response response = call.execute(); System.out.println(response.body().string());}
  • 上传文件
@Testpublic void testUpload() throws IOException { String api = "/api/files/1"; String url = String.format("%s%s", BASE\_URL, api); RequestBody requestBody = new MultipartBody.Builder()   .setType(MultipartBody.FORM)   .addFormDataPart("file", "docker\_practice.pdf",     RequestBody.create(MediaType.parse("multipart/form-data"),       new File("C:/Users/hetiantian/Desktop/学习/docker\_practice.pdf")))   .build(); Request request = new Request.Builder()   .url(url)   .post(requestBody)  //默认为GET请求,可以不写   .build(); final Call call = client.newCall(request); Response response = call.execute(); System.out.println(response.body().string());}

通过 addFormDataPart 方法模拟表单方式上传文件

DELETE 请求:

@Testpublic void testDelete() throws IOException {  String url = String.format("%s%s", BASE\_URL, api);  //请求参数  Request request = new Request.Builder()          .url(url)          .delete()          .build();  final Call call = client.newCall(request);  Response response = call.execute();  System.out.println(response.body().string());}

请求的取消:

@Testpublic void testCancelSysnc() throws IOException {    String api = "/api/files/1";    String url = String.format("%s%s", BASE\_URL, api);    Request request = new Request.Builder()            .url(url)            .get()            .build();    final Call call = client.newCall(request);    Response response = call.execute();    long start = System.currentTimeMillis();    //测试连接的取消    while (true) {         //1分钟获取不到结果就取消请求        if (System.currentTimeMillis() - start > 1000) {            call.cancel();            System.out.println("task canceled");            break;        }    }

    System.out.println(response.body().string());}

调用 cancel 方法进行取消 测试结果:

task canceledcost 9110 msc

java.net.SocketException: socket closed...【省略】

小结

  • OkHttp 使用 build 模式创建对象来的更简洁一些,并且使用. post/.delete/.put/.get 方法表示请求类型,不需要像 HttpClient 创建 HttpGet、HttpPost 等这些方法来创建请求类型
  • 依赖包上,如果 HttpClient 需要发送异步请求、实现文件上传,需要额外的引入异步请求依赖
  <dependency>  <groupId>org.apache.httpcomponentsgroupId>  <artifactId>httpmimeartifactId>  <version>4.5.3version> dependency>

 <dependency>  <groupId>org.apache.httpcomponentsgroupId>  <artifactId>httpasyncclientartifactId>  <version>4.5.3version> dependency>
  • 请求的取消,HttpClient 使用 abort 方法,OkHttp 使用 cancel 方法,都挺简单的,如果使用的是异步 client,则在抛出异常时调用取消请求的方法即可

超时设置

HttpClient 超时设置:在 HttpClient4.3 + 版本以上,超时设置通过 RequestConfig 进行设置

private CloseableHttpClient httpClient = HttpClientBuilder.create().build();private RequestConfig requestConfig =  RequestConfig.custom()        .setSocketTimeout(60 \* 1000)        .setConnectTimeout(60 \* 1000).build();String api = "/api/files/1";String url = String.format("%s%s", BASE\_URL, api);HttpGet httpGet = new HttpGet(url);httpGet.setConfig(requestConfig);  //设置超时时间

超时时间是设置在请求类型 HttpGet 上,而不是 HttpClient 上

OkHttp 超时设置:直接在 OkHttp 上进行设置

private OkHttpClient client = new OkHttpClient.Builder()        .connectTimeout(60, TimeUnit.SECONDS)//设置连接超时时间        .readTimeout(60, TimeUnit.SECONDS)//设置读取超时时间        .build();

小结:如果 client 是单例模式,HttpClient 在设置超时方面来的更灵活,针对不同请求类型设置不同的超时时间,OkHttp 一旦设置了超时时间,所有请求类型的超时时间也就确定

HttpClient 和 OkHttp 性能比较

测试环境:

  • CPU 六核
  • 内存 8G
  • windows10

每种测试用例都测试五次,排除偶然性

client 连接为单例:

img

client 连接不为单例:

img

单例模式下,HttpClient 的响应速度要更快一些,单位为毫秒,性能差异相差不大 非单例模式下,OkHttp 的性能更好,HttpClient 创建连接比较耗时,因为多数情况下这些资源都会写成单例模式,因此图一的测试结果更具有参考价值

总结

OkHttp 和 HttpClient 在性能和使用上不分伯仲,根据实际业务选择即可

httpclient 设置超时时间_面试官:技术选型,HttpClient还是OkHttp?相关推荐

  1. redis list设置过期时间_面试官:你在Redis中设置过带过期时间的Key吗?

    点击上方小伟后端笔记关注公众号 每天阅读Java干货文章 熟悉Redis的同学应该知道,Redis的每个Key都可以设置一个过期时间,当达到过期时间的时候,这个key就会被自动删除. 在为key设置过 ...

  2. 同时设置超时时间_刚入职的小菜鸡,设错了RPC超时,搞了个线上事故

    上面这张监控图,对于服务端的研发同学来说再熟悉不过了.在日常的系统维护中,『服务超时』应该属于监控报警最多的一类问题. 尤其在微服务架构下,一次请求可能要经过一条很长的链路,跨多个服务调用后才能返回结 ...

  3. python给函数设置超时时间_在 Linux/Mac 下为Python函数添加超时时间的方法

    我们在使用 requests 这类网络请求第三方库时,可以看到它有一个参数叫做 timeout ,就是指在网络请求发出开始计算,如果超过 timeout 还没有收到返回,就抛出超时异常.(当然存在特殊 ...

  4. python给函数设置超时时间_在 Linux/Mac 下为Python函数添加超时时间

    我们在使用 requests 这类网络请求第三方库时,可以看到它有一个参数叫做timeout,就是指在网络请求发出开始计算,如果超过 timeout 还没有收到返回,就抛出超时异常.(当然存在特殊情况 ...

  5. Java中HttpClient设置超时时间

    CloseableHttpClient httpclient = HttpClients.createDefault(); HttpGet httpGet = new HttpGet("ht ...

  6. redis查看key的过期时间_面试官:你在Redis中设置过带过期时间的Key吗?

    点击上方小伟后端笔记关注公众号 每天阅读Java干货文章 熟悉Redis的同学应该知道,Redis的每个Key都可以设置一个过期时间,当达到过期时间的时候,这个key就会被自动删除. 在为key设置过 ...

  7. HttpClient设置超时时间无效

    一开始设置了超时时间但怎么设置都没有效果 后来加上了下面一行 就可以了,因为并不是连接超时,而是因为的确连接上了,但对方一直没有给返回信息,所以要等很久,现在设置了 http.socket.timeo ...

  8. redis查看key的过期时间_面试官:Redis过期后key是怎么样清理的?

    前言 笔者一个同事面试某大厂时问到的一个问题,这里拿来讲讲:Redis过期后key是怎么样清理的? 在Redis中,对于过期key的清理主要有惰性清除,定时清理,内存不够时清理三种方法,下面我们就来具 ...

  9. RestTemplate 设置超时时间

    项目访问量大,频繁调取其他系统接口经常出现项目后台假死现象,发现其他系统掉线重启一段时间必现.查看调用接口,同事直接引用了RestTemplate但是没有设置超时时间->_<-. 两种方式 ...

最新文章

  1. 不是吧!程序员今年在相亲市场上这么受欢迎?
  2. python自带的解释器叫做_python学习
  3. SpringBoot 使用注解实现消息广播功能
  4. Vue Cli3 项目 vue.config.js 配置
  5. FZU 2108 Mod problem
  6. ble开发 linux_嵌入式开发的必备知识点
  7. qq android qav,33 BK.QQAVManager 音视频管理
  8. rust物资刷新机制_rust资源刷新 | 手游网游页游攻略大全
  9. 转置矩阵使用T,Hermite矩阵、正交矩阵、酉矩阵、奇异矩阵、正规矩阵、幂等矩阵
  10. codeblocks怎么编程c语言,如何能使用Codeblocks进行C语言编程操作.doc
  11. fast无线路由器设置服务器,迅捷(Fast)FW150R无线路由器设置
  12. 告诉你怎样学Java才是硬道理(转自chinaitlab)
  13. potainer 日志_分享10个优秀的日志分析工具
  14. 公历转农历C语言课程设计,(只为学习)公历转农历代码以完成,请高手在此代码基础上写出个农历转公历的代码出来...
  15. python find_peaks 源码理解
  16. 生日祝福卡片 html,暖心的卡片生日祝福语
  17. 上海计算机5年制大专学校,上海五年一贯制大专学校有哪些
  18. 如何做好一个中小型企业计算机网络管理员
  19. WPS文档设置空格下划线
  20. 在计算机储存中读写速度最快的是,储存器中存储速度最快的是哪个

热门文章

  1. Lambda表达式的省略模式【应用】
  2. 数组操作的两个常见小问题
  3. 多值参数-定义及作用
  4. 设置元素的宽和高 元素的left和top 元素卷曲出去的值 为元素绑定事件
  5. Spring Cloud Gateway 源码解析(3) —— Predicate
  6. JVM-垃圾收集器与内存分配策略
  7. 一个完整网站的代码_网站优化三步走,怎样给自己的网站做优化?
  8. Jlink-V9详细制作材料(带串口+SW)----小白的福音
  9. vue mixins
  10. 解决appium安装app时某些手机弹出的提示框