浅谈HttpClient、okhttp和RestTemplate的区别

一、HttpClient

1、pom依赖

<!--HttpClient-->
<dependency>
    <groupId>commons-httpclient</groupId>
    <artifactId>commons-httpclient</artifactId>
    <version>3.1</version>
</dependency>

2、HttpClient代码实现

public class HttpClientUtil {
    /**
     * httpClient的get请求方式
     * 使用GetMethod来访问一个URL对应的网页实现步骤:
     * 1.生成一个HttpClient对象并设置相应的参数;
     * 2.生成一个GetMethod对象并设置响应的参数;
     * 3.用HttpClient生成的对象来执行GetMethod生成的Get方法;
     * 4.处理响应状态码;
     * 5.若响应正常,处理HTTP响应内容;
     * 6.释放连接。
     * @param url
     * @param charset
     * @return
     */
    public static String doGet(String url, String charset) {
        //1.生成HttpClient对象并设置参数
        HttpClient httpClient = new HttpClient();
        //设置Http连接超时为5秒
        httpClient.getHttpConnectionManager().getParams().setConnectionTimeout(5000);
        //2.生成GetMethod对象并设置参数
        GetMethod getMethod = new GetMethod(url);
        //设置get请求超时为5秒
        getMethod.getParams().setParameter(HttpMethodParams.SO_TIMEOUT, 5000);
        //设置请求重试处理,用的是默认的重试处理:请求三次
        getMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler());
        String response = "";
        //3.执行HTTP GET 请求
        try {
            int statusCode = httpClient.executeMethod(getMethod);
            //4.判断访问的状态码
            if (statusCode != HttpStatus.SC_OK) {
                System.err.println("请求出错:" + getMethod.getStatusLine());
            }
            //5.处理HTTP响应内容
            //HTTP响应头部信息,这里简单打印
            Header[] headers = getMethod.getResponseHeaders();
            for(Header h : headers) {
                System.out.println(h.getName() + "---------------" + h.getValue());
            }
            //读取HTTP响应内容,这里简单打印网页内容
            //读取为字节数组
            byte[] responseBody = getMethod.getResponseBody();
            response = new String(responseBody, charset);
            System.out.println("-----------response:" + response);
            //读取为InputStream,在网页内容数据量大时候推荐使用
            //InputStream response = getMethod.getResponseBodyAsStream();
        } catch (HttpException e) {
            //发生致命的异常,可能是协议不对或者返回的内容有问题
            System.out.println("请检查输入的URL!");
            e.printStackTrace();
        } catch (IOException e) {
            //发生网络异常
            System.out.println("发生网络异常!");
        } finally {
            //6.释放连接
            getMethod.releaseConnection();
        }
        return response;
    }
    /**
     * post请求
     * @param url
     * @param json
     * @return
     */
    public static String doPost(String url, JSONObject json){
        HttpClient httpClient = new HttpClient();
        PostMethod postMethod = new PostMethod(url);
        postMethod.addRequestHeader("accept", "*/*");
        postMethod.addRequestHeader("connection", "Keep-Alive");
        //设置json格式传送
        postMethod.addRequestHeader("Content-Type", "application/json;charset=GBK");
        //必须设置下面这个Header
        postMethod.addRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36");
        //添加请求参数
        postMethod.addParameter("commentId", json.getString("commentId"));
        String res = "";
        try {
            int code = httpClient.executeMethod(postMethod);
            if (code == 200){
                res = postMethod.getResponseBodyAsString();
                System.out.println(res);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return res;
    }
    public static void main(String[] args) {
        System.out.println(doGet("http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=13026194071", "GBK"));
        System.out.println("-----------分割线------------");
        System.out.println("-----------分割线------------");
        System.out.println("-----------分割线------------");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("commentId", "13026194071");
        System.out.println(doPost("http://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=13026194071", jsonObject));
    }
}

3、建议

代码复杂,还得操心资源回收等。代码很复杂,冗余代码多,不建议直接使用。

二、okhttp

1、简介

OkHttp是一个高效的HTTP客户端,允许所有同一个主机地址的请求共享同一个socket连接;连接池减少请求延时;透明的GZIP压缩减少响应数据的大小;缓存响应内容,避免一些完全重复的请求

当网络出现问题的时候OkHttp依然坚守自己的职责,它会自动恢复一般的连接问题,如果你的服务有多个IP地址,当第一个IP请求失败时,OkHttp会交替尝试你配置的其他IP,OkHttp使用现代TLS技术(SNI, ALPN)初始化新的连接,当握手失败时会回退到TLS 1.0。

2、pom依赖

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

它的请求/响应 API 使用构造器模式builders来设计,它支持阻塞式的同步请求和带回调的异步请求。

3、配置文件

@Configuration
public class OkHttpConfig {
    @Bean
    public OkHttpClient okHttpClient() {
        return new OkHttpClient.Builder()
                //.sslSocketFactory(sslSocketFactory(), x509TrustManager())
                .retryOnConnectionFailure(false)
                .connectionPool(pool())
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30,TimeUnit.SECONDS)
                .build();
    }
    @Bean
    public X509TrustManager x509TrustManager() {
        return new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }
            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };
    }
    @Bean
    public SSLSocketFactory sslSocketFactory() {
        try {
            //信任任何链接
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{x509TrustManager()}, new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * Create a new connection pool with tuning parameters appropriate for a single-user application.
     * The tuning parameters in this pool are subject to change in future OkHttp releases. Currently
     */
    @Bean
    public ConnectionPool pool() {
        return new ConnectionPool(200, 5, TimeUnit.MINUTES);
    }
}

4、客户端工具

@Slf4j
public class OkHttpClient {
    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
    private volatile static okhttp3.OkHttpClient client;
    private static final int MAX_IDLE_CONNECTION = Integer
            .parseInt(ConfigManager.get("httpclient.max_idle_connection"));
    private static final long KEEP_ALIVE_DURATION = Long
            .parseLong(ConfigManager.get("httpclient.keep_alive_duration"));
    private static final long CONNECT_TIMEOUT = Long.parseLong(ConfigManager.get("httpclient.connectTimeout"));
    private static final long READ_TIMEOUT = Long.parseLong(ConfigManager.get("httpclient. "));
    /**
     * 单例模式(双重检查模式) 获取类实例
     *
     * @return client
     */
    private static okhttp3.OkHttpClient getInstance() {
        if (client == null) {
            synchronized (okhttp3.OkHttpClient.class) {
                if (client == null) {
                    client = new okhttp3.OkHttpClient.Builder()
                            .connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
                            .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
                            .connectionPool(new ConnectionPool(MAX_IDLE_CONNECTION, KEEP_ALIVE_DURATION,
                                    TimeUnit.MINUTES))
                            .build();
                }
            }
        }
        return client;
    }
    public static String syncPost(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 = OkHttpClient.getInstance().newCall(request).execute();
            if (response.isSuccessful()) {
                String result = response.body().string();
                log.info("syncPost response = {}, responseBody= {}", response, result);
                return result;
            }
            String result = response.body().string();
            log.info("syncPost response = {}, responseBody= {}", response, result);
            throw new IOException("三方接口返回http状态码为" + response.code());
        } catch (Exception e) {
            log.error("syncPost() url:{} have a ecxeption {}", url, e);
            throw new RuntimeException("syncPost() have a ecxeption {}" + e.getMessage());
        }
    }
    public static String syncGet(String url, Map<String, Object> headParamsMap) throws IOException {
        Request request;
        final Request.Builder builder = new Request.Builder().url(url);
        try {
            if (!CollectionUtils.isEmpty(headParamsMap)) {
                final Iterator<Map.Entry<String, Object>> iterator = headParamsMap.entrySet()
                        .iterator();
                while (iterator.hasNext()) {
                    final Map.Entry<String, Object> entry = iterator.next();
                    builder.addHeader(entry.getKey(), (String) entry.getValue());
                }
            }
            request = builder.build();
            Response response = OkHttpClient.getInstance().newCall(request).execute();
            String result = response.body().string();
            log.info("syncGet response = {},responseBody= {}", response, result);
            if (!response.isSuccessful()) {
                throw new IOException("三方接口返回http状态码为" + response.code());
            }
            return result;
        } catch (Exception e) {
            log.error("remote interface url:{} have a ecxeption {}", url, e);
            throw new RuntimeException("三方接口返回异常");
        }
    }
}

三、RestTemplate

1、pom依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2、get请求(不带参的即把参数取消即可)

// 1-getForObject()
User user1 = this.restTemplate.getForObject(uri, User.class);
// 2-getForEntity()
ResponseEntity<User> responseEntity1 = this.restTemplate.getForEntity(uri, User.class);
HttpStatus statusCode = responseEntity1.getStatusCode();
HttpHeaders header = responseEntity1.getHeaders();
User user2 = responseEntity1.getBody();

// 3-exchange()
RequestEntity requestEntity = RequestEntity.get(new URI(uri)).build();
ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class);
User user3 = responseEntity2.getBody();

方式一:

Notice notice = restTemplate.getForObject("http://fantj.top/notice/list/{1}/{2}"
                , Notice.class,1,5);

方式二:

Map<String,String> map = new HashMap();
map.put("start","1");
map.put("page","5");
Notice notice = restTemplate.getForObject("http://fantj.top/notice/list/"
        , Notice.class,map);

3、post请求

// 1-postForObject()
User user1 = this.restTemplate.postForObject(uri, user, User.class);
// 2-postForEntity()
ResponseEntity<User> responseEntity1 = this.restTemplate.postForEntity(uri, user, User.class);
// 3-exchange()
RequestEntity<User> requestEntity = RequestEntity.post(new URI(uri)).body(user);
ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class);

方式一:

String url = "http://demo/api/book/";
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
headers.setContentType(type);
String requestJson = "{...}";
HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
String result = restTemplate.postForObject(url, entity, String.class);
System.out.println(result);

方式二:

@Test
public void rtPostObject(){
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://47.xxx.xxx.96/register/checkEmail";
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
    map.add("email", "844072586@qq.com");

    HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
    ResponseEntity<String> response = restTemplate.postForEntity( url, request , String.class );
    System.out.println(response.getBody());
}

使用RestTemplate需注意:

使用RestTemplate发送请求,当请求体是String时,应这样配置:

RestTemplate restTemplate = new RestTemplate(factory);
        restTemplate
          .getMessageConverters()
          .set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));

如果没有自定义StringHttpMessageConverter,默认的StringHttpMessageConverter使用的字符集是ISO_8859_1,当请求体包含中文时,会乱码。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 如何使用Spring RestTemplate访问restful服务

    一. 什么是RestTemplate Spring's central class for synchronous client-side HTTP access. It simplifies communication with HTTP servers, and enforces RESTful principles. It handles HTTP connections, leaving application code to provide URLs(with possible tem

  • Spring远程调用HttpClient/RestTemplate的方法

    一.HttpClient 两个系统间如何互相访问?两个tomcat上的项目如何互相访问? 采用HttpClient实现跨系统的接口调用. 介绍: 官网:http://hc.apache.org/index.html 现在也叫:HttpComponents HttpClient可以发送get.post.put.delete....等请求 使用: 导入坐标 <dependency> <groupId>org.apache.httpcomponents</groupId> &

  • 解决Feign切换client到okhttp无法生效的坑(出现原因说明)

    提示:如果只看如何解决问题,请看文章的末尾如何解决这个问题 1. 场景描述 最近项目中使用了feign当做http请求工具来使用.相对于httpclient.resttemplate来说,fegin用起来方便很多. 然后项目有httptrace的需求,需要输出请求日志. 所以就开启了feign自己的日志,发现它自带的日志是debug级别才能打印.而且是逐行打印的,看日志非常的不方便.所以需要输出json格式的日志最好. 2.解决步骤 2.1 引入feign依赖 <dependency> <

  • 关于springboot 中使用httpclient或RestTemplate做MultipartFile文件跨服务传输的问题

    大家好,因为近期做需求中遇到了文件上传这个东西,而且我这个还是跨服务去传输文件的所以我这边使用了httpclient和RestTemplate去做,但是最后还是用的httpclient.feign和RestTemplate在超大文件下会OOM所以适用于小文件传输我这边测试的在1G以下.httpclient好像是无限哈哈哈.(具体多少大家有时间可以去测一下) 1.被调用服务的Controller 1.这块使用@RequestParam("file")或者@RequestPart(&quo

  • 详解SpringBoot中RestTemplate的几种实现

    RestTemplate的多种实现 使用JDK默认的http library 使用Apache提供的httpclient 使用Okhttp3 @Configuration public class RestConfig { @Bean public RestTemplate restTemplate(){ RestTemplate restTemplate = new RestTemplate(); return restTemplate; } @Bean("urlConnection"

  • 浅谈jQuery before和insertBefore的区别

    jQuery 中利用before和insertBefore可以达到在指定元素前插入指定内容,写法上有区别 先看一个例子: 在<div class='div1'>div1</div>前面插入<div>toInsertContent</div> 实现: $('<div>toInsertContent</div>').insertBefore($('.div1')); 或者 $('.div1').before('<div>toI

  • 浅谈mybatis中的#和$的区别 以及防止sql注入的方法

    mybatis中的#和$的区别 1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号.如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id". 2. $将传入的数据直接显示生成在sql中.如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id,  如果传入的

  • 浅谈JS函数定义方式的区别

    关于JS的函数定义方式有以下两种: (1)典型的函数声明 function slide(arguments){ //...code } (2)以函数表达式的形式定义函数 var slide = function(arguments){ //...code } 虽然上面两种方式逻辑上是等价的,但是还是有点小区别: 区别一:例一中的函数会在代码执行以前被加载到作用域中,而例二则是在代码执行到那一行的时候才会有定 义: 区别二:函数声明会给函数指定一个名字,而函数表达式则是创建一个匿名函数,然后将这个

  • 浅谈Linux 脚本 sh 和 ./ 的区别

    如果.不在PATH里面,要执行当前目录下的可执行文件,使用全路径: ./executable-file PATH是环境变量,如果将当前目录"./"添加到环境变量中,那么也可以不用"./",直接输入当前目录下有可执行权限的可执行文件就可以运行了 如果要执行一个sh脚本,不管那个脚本有没有可执行权限,都可以使用: sh [file] 这时file是作为参数传给sh的,如果file不在当前目录下,也需要使用全路径. 全路径有绝对路径和相对路径两种../和../开头的都是相

  • 浅谈jQuery this和$(this)的区别及获取$(this)子元素对象的方法

    1.JQuery this和$(this)的区别 相信很多刚接触JQuery的人,很多都会对$(this)和this的区别模糊不清,那么这两者有什么区别呢? 首先来看看JQuery中的  $()  这个符号,实际上这个符号在JQuery中相当于JQuery(),即$(this)=jquery();也就是说,这样可以返回一个jquery对象.那么,当你在网页中alert($('#id'));时,会弹出一个[object Object ],这个object对象,也就是jquery对象了. 那么,我们

  • 浅谈mwArray和一般数组的区别

    可以用下面的代码详细理解mwArray和一般数组之间的区别 mwArray a(3, 2, mxDOUBLE_CLASS); double *aData; aData = new double[6]; int iii; for( iii=0; iii<6; ++iii) { aData[iii] = iii+1; } // print output std::cout << "a = " << std::endl; std::cout << a

  • 浅谈spring和spring MVC的区别与关系

    spring是一个开源框架,功能主要是依赖注入和控制反转. 依赖注入有三种形式 1.构造注入(bytype) 2.setter注入 3.接口注入(byname) 而控制反转则主要是起到操控作用,把对象的创建,初始化,销毁交给spring容器来处理.面向切面(把功能分离出来)实现共用. spring MVC类似于struts是负责前台和后台的交互,还有就是spring可以集成许多工具,像数据库配置,缓存配置,定时器配置等等都是在spring中完成的,而spring MVC是做不到的. 以上这篇浅谈

  • 浅谈mybatis中的#和$的区别

    1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号.如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by "111", 如果传入的值是id,则解析成的sql为order by "id". 2. $将传入的数据直接显示生成在sql中.如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id, 如果传入的值是id,则解析成的sql为ord

  • 浅谈Arrays.asList() 和ArrayList类型区别

    <pre name="code" class="html"><pre name="code" class="html">Arrays.asList() 将一个数组转化为一个List对象,这个方法会返回一个ArrayList类型的对象, 这个ArrayList类并非java.util.ArrayList类,而是Arrays类的静态内部类!用这个对象对列表进行添加删除更新操作,就会报UnsupportedO

  • 浅谈sklearn中predict与predict_proba区别

    predict_proba 返回的是一个 n 行 k 列的数组,列是标签(有排序), 第 i 行 第 j 列上的数值是模型预测 第 i 个预测样本为某个标签的概率,并且每一行的概率和为1. predict 直接返回的是预测 的标签. 具体见下面示例: # conding :utf-8 from sklearn.linear_model import LogisticRegression import numpy as np x_train = np.array([[1,2,3], [1,3,4]

随机推荐