美文网首页
HTTP客户端调研-20190125

HTTP客户端调研-20190125

作者: 打不过猫的鱼 | 来源:发表于2019-03-01 20:23 被阅读0次

我们想要一个什么样的?

理想型的HTTP库应当具备以下能力:

  • 提供分析记录请求各个阶段的能力,如在什么时候发送数据、在什么接收数据、各阶段的耗时
  • 支持响应缓存减少重复的网络请求
  • 支持重试
  • 支持连接池能复用连接
  • 简单易用
  • 支持HTTP/1.0、HTTP/1.1、HTTP/2.0
  • 支持同步和异步请求
  • 支持取消请求
  • 支持设置超时

目前有哪些可选的,哪一个和我们匹配度最高的?

可以发起http请求的组件:

  • JDK's URLConnection uses traditional thread-blocking I/O.
  • Apache HTTP Client uses traditional thread-blocking I/O with thread-pools.
  • Apache Async HTTP Client uses NIO.
  • Jersey is a RESTful client/server framework; the client API can use several HTTP client backends including URLConnection and Apache HTTP Client.
  • OkHttp uses traditional thread-blocking I/O with thread-pools.
  • Retrofit turns your HTTP API into a Java interface and can use several HTTP client backends including Apache HTTP Client.
  • Grizzly is network framework with low-level HTTP support; it was using NIO but it switched to AIO .
  • Netty is a network framework with HTTP support (low-level), multi-transport, includes NIO and native (the latter uses epoll on Linux).
  • Jetty Async HTTP Client uses NIO.
  • Async HTTP Client wraps either Netty, Grizzly or JDK's HTTP support.
  • clj-http wraps the Apache HTTP Client.is an async subset of clj-http implemented partially in Java directly on top of NIO.
  • http async client wraps the Async HTTP Client for Java.

下面挑选主流且大家熟悉的做个对比:

结论

HttpURLConnection封装层次太低,支持的特性也比较少,因此不在我们的选择范围内;对比Apache HttpClient跟OkHttp,在功能跟性能上来看是不相上下的;

  • 在稳定性上Apache HttpClient历史悠久,稳定性更好;
  • 在社区活跃度上OkHttp更胜一筹,GitHub上星标达到30000+,可以说是当下最流行的Http库了;从安卓4.4版本开始就使用okhttp来处理http请求。
  • 在扩展性上OkHttp更加方便用户定制个性化的扩展功能,如我们可以很方便的监控Http请求,在无需客户端配合的情况下,尽可能的保留更多的信息;
  • 在易用性上,流式的构建者模式和不可变模式使得OkHttp更胜一筹;

在最终权衡下,决定使用OkHttp。

OkHttp:

官方文档:http://square.github.io/okhttp/
git源码:https://github.com/square/okhttp

  • 官网介绍:

  • 官方示例

    package okhttp3.guide;
    
    import java.io.IOException;
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.Response;
    
    public class GetExample {
      OkHttpClient client = new OkHttpClient();
    
      String run(String url) throws IOException {
        Request request = new Request.Builder()
            .url(url)
            .build();
    
        try (Response response = client.newCall(request).execute()) {
          //string()方法只能调用一次,因为调用后会关闭流
          return response.body().string();
        }
      }
    
      public static void main(String[] args) throws IOException {
        GetExample example = new GetExample();
        String response = example.run("https://raw.github.com/square/okhttp/master/README.md");
        System.out.println(response);
      }
    }
    
    package okhttp3.guide;
    
    import java.io.IOException;
    import okhttp3.MediaType;
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.RequestBody;
    import okhttp3.Response;
    
    public class PostExample {
      public static final MediaType JSON = MediaType.get("application/json; charset=utf-8");
    
      OkHttpClient client = new OkHttpClient();
    
      String post(String url, String json) throws IOException {
        RequestBody body = RequestBody.create(JSON, json);
        Request request = new Request.Builder()
            .url(url)
            .post(body)
            .build();
        try (Response response = client.newCall(request).execute()) {
          //string()方法只能调用一次,因为调用后会关闭流
          return response.body().string();
        }
      }
    
      String bowlingJson(String player1, String player2) {
        return "{'winCondition':'HIGH_SCORE',"
            + "'name':'Bowling',"
            + "'round':4,"
            + "'lastSaved':1367702411696,"
            + "'dateStarted':1367702378785,"
            + "'players':["
            + "{'name':'" + player1 + "','history':[10,8,6,7,8],'color':-13388315,'total':39},"
            + "{'name':'" + player2 + "','history':[6,10,5,10,10],'color':-48060,'total':41}"
            + "]}";
      }
    
      public static void main(String[] args) throws IOException {
        PostExample example = new PostExample();
        String json = example.bowlingJson("Jesse", "Jake");
        String response = example.post("http://www.roundsapp.com/post", json);
        System.out.println(response);
      }
    }
    
     OkHttpClient client = new OkHttpClient.Builder().readTimeout(5, TimeUnit.SECONDS).build();
     Request request = new Request.Builder().url("http://www.baidu.com").get().build();
     Call call = client.newCall(request);
     call.enqueue(new Callback() {
         @Override
         public void onFailure(Call call, IOException e) {
             System.out.println("Fail");
         }
    
         @Override
         public void onResponse(Call call, Response response) throws IOException {
              System.out.println(response.body().string());
         }
     });
    
    
  • 注意点

    ①每次new OkHttpClient(); 都会创建一个连接池和线程池,所以要保证只new一次OkHttpClient()。可以使用newBuilder()来为不同的目标地址配置参数。

    ②异步请求:最多并发64个,同一个host的访问不能超过5个,否则进入等待队列。

    ③连接池:默认空闲连接数是5,每个连接最多存活时间是5分钟,连接池大小取决于内存大小(无限量)。

    ④超时:默认的connectTimeout,readTimeout,writeTimeout都是10s。

    ⑤缓存:OKHttp的网络缓存是基于http协议,使用lru策略;目前只支持GET,其他请求方式需要自己实现。需要服务器配合,通过head设置相关头来控制缓存,创建OkHttpClient时候需要配置Cache。

    ⑥Cookie:OKHttp默认是没有提供Cookie管理功能的,所以如果想增加Cookie管理需要重写CookieJar里面的方法。

    ⑦服务器主动断开的链接如何处理?OkHttp则不会进行连接判断,直接发送请求,如果服务端在接收请求后回复RST消息,OkHttp会重新建立连接后再发送请求。OkHttp由于没有检查连接状态,在服务端主动断开连接时,会发送无效请求,对于服务端来说,就降低了请求成功率。可以通过设置ConnectionPool的Keep-Alive时间来解决这个问题,默认值为5min。只要配置时间短于服务端对应的时间,就可以保证由客户端主动断开连接,就不会出现无效请求的问题。

    ⑧过滤器:官网写的非常清楚,传送门:https://github.com/square/okhttp/wiki/Interceptors#choosing-between-application-and-network-interceptors

    ⑨重试策略:

/**
   * Report and attempt to recover from a failure to communicate with a server. Returns true if
   * {@code e} is recoverable, or false if the failure is permanent. Requests with a body can only
   * be recovered if the body is buffered or if the failure occurred before the request has been
   * sent.
   */
  private boolean recover(IOException e, boolean requestSendStarted, Request userRequest) {
    streamAllocation.streamFailed(e);
     // 1\. 应用层配置不在连接,默认为true
    // The application layer has forbidden retries.
    if (!client.retryOnConnectionFailure()) return false;
     // 2\. 请求Request出错不能继续使用
    // We can't send the request body again.
    if (requestSendStarted && userRequest.body() instanceof UnrepeatableRequestBody) return false;
    //  是否可以恢复的
    // This exception is fatal.
    if (!isRecoverable(e, requestSendStarted)) return false;
    // 4\. 没有更多线路可供选择
    // No more routes to attempt.
    if (!streamAllocation.hasMoreRoutes()) return false;

    // For failure recovery, use the same route selector with a new connection.
    return true;
  }
  1. 若应用层配置的是不再连接(默认为true),则不可恢复。(可通过设置retryOnConnectionFailure来改变)

  2. 请求Request是不可重复使用的Request,则不可恢复

  3. 根据Exception的类型判断是否可以恢复的 (isRecoverable()方法)
    3.1、如果是协议错误(ProtocolException)则不可恢复
    3.2、如果是中断异常(InterruptedIOException)则不可恢复
    3.3、如果是SSL握手错误(SSLHandshakeException && CertificateException)则不可恢复
    3.4、certificate pinning错误(SSLPeerUnverifiedException)则不可恢复

  4. 没有更多线路可供选择 则不可恢复

  5. 如果上述条件都不满足,则这个request可以恢复,最大重试20次。

    举例:UnknownHostException不会重试;读写超时导致的SocketTimeoutException,要看是否已经发送了request,若已发送则不重试。连接超时导致的SocketTimeoutException,若没有其他路由则不重试,有则重试。

  • 请求响应流程如下:
  • 核心类
  • 调用流程说明

    如果有自定义的过滤器,先执行自定义的。

相关文章

  • HTTP客户端调研-20190125

    我们想要一个什么样的? 理想型的HTTP库应当具备以下能力: 提供分析记录请求各个阶段的能力,如在什么时候发送数据...

  • 分享我们团队内部的Flutter技术调研报告-20190125

    Flutter技术调研报告-20190125 作者: Android团队 - 余天然 杨继宇 1.Flutter简...

  • 2019年会

    20190125 2019会更好!

  • Zuul的多个使用场景

    Zuul Http客户端 Zuul使用的默认HTTP客户端现在由Apache HTTP Client支持,而不是已...

  • net/http

    http 包实现了http客户端与服务端的实现 1.创建http客户端 2.客户端发起get,post,postF...

  • HTTP

    HTTP是什么 超文本传输协议 http客户端发起请求,创建端口 http服务器在端口监听客户端请求 http服务...

  • node 小记(0418)http

    什么是http及相关知识 http客户端发起请求,创建端口 http服务器在端口监听客户端请求 http服务器向客...

  • 新浪财经&网易财经 竞品分析报告

    1竞品调研概述 1.1调研简介 本次调研选取的是两大传统门户网站-新浪、网易的财经资讯类客户端,通过产品功能、用户...

  • HTTP请求和响应

    1.HTTP工作原理 HTTP协议工作于客户端-服务端架构上。浏览器作为HTTP客户端通过URL向HTTP服务端即...

  • node.js-http模块深入理解

    http模块主要用于搭建HTTP服务端和客户端,使用HTTP服务器或客户端功能都必须调用http模块。 创建服务器...

网友评论

      本文标题:HTTP客户端调研-20190125

      本文链接:https://www.haomeiwen.com/subject/cbujuqtx.html