余晖落尽暮晚霞,黄昏迟暮远山寻
本站
当前位置:网站首页 > 编程知识 > 正文

HTTP通讯框架选型HttpClient/OkHttp(abb框架断路器选型手册)

xiyangw 2022-11-24 16:41 58 浏览 0 评论

最近在总结项目中,其中包含调用第三方做HTTP通讯的处理,主要涉及了两类通讯框架的依赖,即HttpClient和OkHttp;

虽然,HTTP协议目前已经进化到HTTP2了,但有没有发现,在HTTP客户端调用这一层很少用到HTTP2的特性;

下面就HttpClient及OkHttp在项目中的使用、及遇到的问题做简单说明。

HttpClient

传送门

https://hc.apache.org

说明

HttpClient被用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。

特性:

基于标准、纯净的java语言。实现了Http1.0和Http1.1

以可扩展的面向对象的结构实现了Http全部的方法(GET, POST, PUT, DELETE, HEAD, OPTIONS, and TRACE)。

支持HTTPS协议。

通过Http代理建立透明的连接。

利用CONNECT方法通过Http代理建立隧道的https连接。

Basic, Digest, NTLMv1, NTLMv2, NTLM2 Session, SNPNEGO/Kerberos认证方案。

插件式的自定义认证方案。

便携可靠的套接字工厂使它更容易地使用第三方解决方案。

连接管理器支持多线程应用。支持设置最大连接数,同时支持设置每个主机的最大连接数,发现并关闭过期的连接。

自动处理Set-Cookie中的Cookie。

插件式的自定义Cookie策略。

Request的输出流可以避免流中内容直接缓冲到socket服务器。

Response的输入流可以有效的从socket服务器直接读取相应内容。

在http1.0和http1.1中利用KeepAlive保持持久连接。

直接获取服务器发送的response code和 headers。

设置连接超时的能力。

实验性的支持http1.1 response caching。

源代码基于Apache License 可免费获取。


使用步骤:

创建HttpClient对象

创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象

如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HttpParams params)方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数

调用HttpClient对象的execute(HttpUriRequest request)方法发送请求,该方法返回一个HttpResponse

调用HttpResponse的getAllHeaders()、getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponse的getEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容

释放连接。无论执行方法是否成功,都必须释放连接

Get

public void get() {   
    CloseableHttpClient httpclient = HttpClients.createDefault();   
    try {   
        // 创建httpget.     
        HttpGet httpget = new HttpGet("http://www.baidu.com/");   
        logger.info("executing request " + httpget.getURI());   
        // 执行get请求.     
        CloseableHttpResponse response = httpclient.execute(httpget);   
        try {   
            // 获取响应实体     
            HttpEntity entity = response.getEntity();   
            System.out.println("--------------------------------------");   
            // 打印响应状态     
            System.out.println(response.getStatusLine());   
            if (entity != null) {   
                // 打印响应内容长度     
                System.out.println("Response content length: " + entity.getContentLength());   
                // 打印响应内容     
                System.out.println("Response content: " + EntityUtils.toString(entity));   
            }   
            System.out.println("------------------------------------");   
        } finally {   
            response.close();   
        }   
    } catch (ClientProtocolException e) {   
        e.printStackTrace();   
    } catch (ParseException e) {   
        e.printStackTrace();   
    } catch (IOException e) {   
        e.printStackTrace();   
    } finally {   
        // 关闭连接,释放资源     
        try {   
            httpclient.close();   
        } catch (IOException e) {   
            e.printStackTrace();   
        }   
    }   
}  

Post

/** 
 * 发送 post请求访问本地应用并根据传递参数不同返回不同结果 
 */   
public void post() {   
    // 创建默认的httpClient实例.     
    CloseableHttpClient httpclient = HttpClients.createDefault();   
    // 创建httppost     
    HttpPost httppost = new HttpPost("http://localhost:8080/myDemo/Ajax/serivceJ.action");   
    // 创建参数队列     
    List<NameValuePair> formparams = new ArrayList<NameValuePair>();   
    formparams.add(new BasicNameValuePair("type", "house"));   
    UrlEncodedFormEntity uefEntity;   
    try {   
        uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");   
        httppost.setEntity(uefEntity);   
        System.out.println("executing request " + httppost.getURI());   
        CloseableHttpResponse response = httpclient.execute(httppost);   
        try {   
            HttpEntity entity = response.getEntity();   
            if (entity != null) {   
                System.out.println("--------------------------------------");   
                System.out.println("Response content: " + EntityUtils.toString(entity, "UTF-8"));   
                System.out.println("--------------------------------------");   
            }   
        } finally {   
            response.close();   
        }   
    } catch (ClientProtocolException e) {   
        e.printStackTrace();   
    } catch (UnsupportedEncodingException e1) {   
        e1.printStackTrace();   
    } catch (IOException e) {   
        e.printStackTrace();   
    } finally {   
        // 关闭连接,释放资源     
        try {   
            httpclient.close();   
        } catch (IOException e) {   
            e.printStackTrace();   
        }   
    }   
}  

文件处理

上传文件

/** 
 * 发送 post请求访问本地应用并根据传递参数不同返回不同结果 
 */   
public void post() {   
    // 创建默认的httpClient实例.     
    CloseableHttpClient httpclient = HttpClients.createDefault();   
    // 创建httppost     
    HttpPost httppost = new HttpPost("http://localhost:8080/myDemo/Ajax/serivceJ.action");   
    // 创建参数队列     
    List<NameValuePair> formparams = new ArrayList<NameValuePair>();   
    formparams.add(new BasicNameValuePair("type", "house"));   
    UrlEncodedFormEntity uefEntity;   
    try {   
        uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");   
        httppost.setEntity(uefEntity);   
        System.out.println("executing request " + httppost.getURI());   
        CloseableHttpResponse response = httpclient.execute(httppost);   
        try {   
            HttpEntity entity = response.getEntity();   
            if (entity != null) {   
                System.out.println("--------------------------------------");   
                System.out.println("Response content: " + EntityUtils.toString(entity, "UTF-8"));   
                System.out.println("--------------------------------------");   
            }   
        } finally {   
            response.close();   
        }   
    } catch (ClientProtocolException e) {   
        e.printStackTrace();   
    } catch (UnsupportedEncodingException e1) {   
        e1.printStackTrace();   
    } catch (IOException e) {   
        e.printStackTrace();   
    } finally {   
        // 关闭连接,释放资源     
        try {   
            httpclient.close();   
        } catch (IOException e) {   
            e.printStackTrace();   
        }   
    }   
}

下载文件

public class FileFetchEngine {

    public String[] fetch(String url,String sysId, String fileType, String filepath, String date)
            throws Exception {
        String tmpfilepath = filepath ;
        CloseableHttpClient httpclient = HttpClients.createDefault();
        FileOutputStream out = null;
        try {
            HttpPost httppost = new HttpPost(url);
            HttpEntity reqEntity = MultipartEntityBuilder.create().build();
            httppost.setEntity(reqEntity);
            
            CloseableHttpResponse response = httpclient.execute(httppost);
            try {
                String ret = "" ;
                HttpEntity resEntity = response.getEntity();
                if (resEntity == null) {
                    return null ;
                }
                if(resEntity.getContentType()==null) {
                    return null ;
                }
                String contentType = resEntity.getContentType().getValue().split(";")[0] ;
                if("text/xml".equals(contentType)) {
                    byte[] content = new byte[(int) resEntity.getContentLength()];
                    resEntity.getContent().read(content);
                    ret = new String(content, "UTF-8");
                    
                    JSONObject retJson = JSONObject.fromObject(ret) ;
                    String retCode = retJson.getString("retCode") ;
                    String retMsg = retJson.getString("retMsg") ;
                    return new String[]{retCode,retMsg};
                } else {
                    File dir = new File(filepath);
                    if(!dir.exists()) {
                        dir.mkdirs() ;
                    }
                    
                    filepath += File.separator+fileType+"_"+date+".txt.gz" ;
                    out = new FileOutputStream(filepath);  
                    int c;
                    while ((c = resEntity.getContent().read()) != -1) {
                        out.write(c);
                    }
                }
                
                try {
                    TarAndGzUtil.unGz(filepath, tmpfilepath);
                } catch (Exception e) { 
                    throw new Exception("文件解压失败!"+e)  ;
                }
                
                EntityUtils.consume(resEntity);
                return new String[]{"0000","下载成功!",filepath};
            } finally {
                response.close();
            }
        } finally {
            try {  
                if (out != null)  
                    out.close();  
            } catch (IOException e) {  
                Enviroment.getEnv().getLogBean().error(e);  
            }
            httpclient.close();
        }
    }
    
}


参考资料

https://blog.csdn.net/w372426096/article/details/82713315

OkHttp

传送门

传送门:https://square.github.io/okhttp/

代码片段:https://square.github.io/okhttp/recipes/

说明

OkHttp是一个高效的HTTP客户端


特性:

支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接

连接池减少请求延时

透明的GZIP压缩减少响应数据的大小

缓存响应内容,避免出现一些完全重复的请求


使用步骤:

创建OkHttpClient对象

创建Request对象

将Request 对象封装为Call

通过Call 来执行同步或异步请求,调用execute方法同步执行,调用enqueue方法异步执行

maven坐标

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

Get(同步)

为什么写异步的处理?因为我在实际业务开发中始终没有遇到异步HTTP处理的场景;

以下是官网的例子

private final OkHttpClient client = new OkHttpClient();

  public void run() throws Exception {
    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());
      IOUtils.closeQuietly(response);
    }
    
  }

Post(项目中用得最多的)

String url = "" ;
String content = "{}";
OkHttpClient client = new OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .writeTimeout(10, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .build();
MediaType mediaType = MediaType.parse("application/json;charset=utf-8");
RequestBody body = RequestBody.create(mediaType, content.toString());
Request request = new Request.Builder()
        .url(url)
        .method("POST", body)
        .addHeader("Content-Type", "application/json;charset=utf-8")
        .build();
try {
    Response response = client.newCall(request).execute();
    String responseMsg = "";
    if (response.isSuccessful()) {
        responseMsg = response.body() == null ? "" : response.body().string();
        JsonObject respJsonObject = new JsonParser()
            .parse(responseMsg)
            .getAsJsonObject();
        // 业务处理
    } else {
        responseMsg = "交易端通讯失败!";
        // 错误处理
    }
    IOUtils.closeQuietly(response);
} catch (Throwable e) {
    // 异常处理
}

注意

  1. 每次response都必须关闭掉,否则会报警,告诉你太多响应没有关闭;
  2. OkHttpClient可以为单例模式,也可以不是;
  3. 非单例模式下,OkHttpClient会维护一个单独的线程池,高并发下会出现连接池线程增多;因此OkHttpClient可以采用同一个连接池的管理对象;或直接使用单例模式;
  4. OkHttpClient中的超时时间设置也很有必要,默认超时时间往往会影响业务效率;

文件处理

上传文件

  public static final MediaType MEDIA_TYPE_MARKDOWN
      = MediaType.parse("text/x-markdown; charset=utf-8");

  private final OkHttpClient client = new OkHttpClient();

  public void run() throws Exception {
    File file = new File("README.md");

    Request request = new Request.Builder()
        .url("https://api.github.com/markdown/raw")
        .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
        .build();

    try (Response response = client.newCall(request).execute()) {
      if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);

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

下载文件

也可查看Get方式的处理,本身就是一个文件下载的例子;

在get的基础上,获取到response后将response返回的stream写到文件里面即可

private final OkHttpClient client = new OkHttpClient();

public void run() throws Exception {
    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);

      File file = new File("");
      writeFile(file,response);
      
    }
}

private void writeFile(File file,Response response) {
    OutputStream outputStream = null;
    InputStream inputStream = response.body().byteStream();
    try {
        outputStream = new FileOutputStream(file);
        int len = 0;
        byte[] buffer = new byte[1024*10];
        while ((len = inputStream.read(buffer))!=-1){
            outputStream.write(buffer,0,len);
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        try {
            if(inputStream != null)
                inputStream.close();
            if(outputStream != null)
                outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


你看,奇怪的知识是不是又增加了!

相关推荐

数控系统常见术语详解,机加工人士必备资料
数控系统常见术语详解,机加工人士必备资料

增量编码器(Incrementpulsecoder)回转式位置测量元件,装于电动机轴或滚珠丝杠上,回转时发出等间隔脉冲表示位移量。由于没有记忆元件,故不能准...

2023-09-24 17:42 xiyangw

功、功率、扭矩的关系

功=功率×时间work=power×timeW=P×T功=力×距离work=force×lengthW=F×LP×T=F×LP=F×L/T=F×V(velocity)具体到电机输出轴上,圆...

Wi-Fi协议(802.11 )常见专业术语汇总
Wi-Fi协议(802.11 )常见专业术语汇总

Wi-Fi协议(802.11)常见专业术语汇总AP(Accesspoint的简称,即访问点,接入点):是一个无线网络中的特殊节点,通过这个节点,无线网络中的...

2023-09-24 17:41 xiyangw

不需要策略模式也能避免满屏if/else
不需要策略模式也能避免满屏if/else

满屏if/elsejava复制代码publicstaticvoidmain(String[]args){inta=1;if...

2023-09-24 17:41 xiyangw

喜极而泣,我终于干掉了该死的 if-else
喜极而泣,我终于干掉了该死的 if-else

推荐阅读:面试淘宝被Tomcat面到“自闭”,学习这份文档之后“吊打”面试官刷完spring+redis+负载均衡+netty+kafka面试题,再去面试BAT...

2023-09-24 17:40 xiyangw

Python中使用三元运算符简化if-else语句
Python中使用三元运算符简化if-else语句

Python是一种极简主义的编程语言,相比其他编程语言,在多个地方简化了代码的写法,可以让我们用更少的时间更简洁地完成工作。以赋值运算符为例:a=a+b简化...

2023-09-24 17:40 xiyangw

雅思课堂 | 雅思口语写作句型第二讲
雅思课堂 | 雅思口语写作句型第二讲

纯干货,无废话用最少的时间学最制胜的内容!泡图书馆泡不过学霸?碎片时间也能弯道超车!向着雅思8分行动起来吧!雅思口语写作句型1.Ipreferseeing...

2023-09-24 17:39 xiyangw

设计模式(三)——简单的状态模式代替if-else
设计模式(三)——简单的状态模式代替if-else

博主将会针对Java面试题写一组文章,包括J2ee,SQL,主流Web框架,中间件等面试过程中面试官经常问的问题,欢迎大家关注。一起学习,一起成长。前言大多数开...

2023-09-24 17:38 xiyangw

如何优化代码中大量的if/else,switch/case?

前言随着项目的迭代,代码中存在的分支判断可能会越来越多,当里面涉及到的逻辑比较复杂或者分支数量实在是多的难以维护的时候,我们就要考虑下,有办法能让这些代码变得更优雅吗?正文使用枚举这里我们简单的定义一...

优秀程序员早就学会用“状态模式”代替if-else了
优秀程序员早就学会用“状态模式”代替if-else了

2020年已经进入倒计时了,大家立好的flag完成了吗?2020实“鼠”不易,希望2021可以“牛”转乾坤。简介状态模式是行为型设计模式的一种。其设计理念是当对...

2023-09-24 17:37 xiyangw

用Select Case语句对执行多条件进行控制
用Select Case语句对执行多条件进行控制

今日的内容是"VBA之EXCEL应用"的第六章"条件判断语句(If...Then...Else)在VBA中的利用"。这讲是第三节...

2023-09-24 17:37 xiyangw

c#入门教程(四)条件判断if else

条件判断,是编程里常用的判断语句,比如某个代码如果满足条件就执行a代码块否则就执行b代码块。案例1:inti=2*5;if(a>0){执行a代码块}elseif(a<0){执行b代码块...

每日学编程之JAVA(十一)—条件语句(if……else)

一个if语句包含一个布尔表达式和一条或多条语句。如果布尔表达式的值为true,则执行if语句中的代码块,否则执行if语句块后面的代码。if语句后面可以跟else语句,当if语句...

不需要策略模式也能避免满屏if/else

除了使用策略模式以外,还可以使用其他设计模式来避免满屏if/else的问题。以下是一些可能的解决方案:工厂模式:将if/else语句移到工厂类中,由工厂类负责创建对象。这样可以将if/else语句从客...

围绕ifelse与业务逻辑的那些梗
围绕ifelse与业务逻辑的那些梗

ifelse很重要,几乎是程序员编程核心,业务逻辑与规则也通过ifelse体现出来,语句简单但是背后文章很大,先看几则幽默图:1.也许默认使用returnf...

2023-09-24 17:36 xiyangw

取消回复欢迎 发表评论: