关于Http工具类的思考

HTTP工具类

说明

每个服务发展到一定阶段,必不可少的需要调用外部服务,目前最常见,最通用的就是HTTP协议了,由此我们发展出来HTTP工具类。每个团队发展出了适合自己用的Http工具类,拿我个人举例,根据我不同阶段不同水平接触它,对它的要求也越来越不一样:

实现功能即可 ----> 要求简洁方便,一句代码解决 ----> 功能强大,支持我的各种header需求,支持Https,各种返回类型的需求(能转化成我想要的java对象最好了) ----> 还要能看到状态码,异常不要自己说吃掉就吃掉 ----> 需要支持我的请求和响应日志,同时不要把我最烦人的日志打印出来(文件流) ----> 考虑到以后业务需求,我还想在请求前和请求后做点东西,统一处理部分Http,要求动态扩展 ---->支持这么多功能,仍要有一套统一的调用方法,最终要简单易用 

慢慢的将Http工具基于Http Client完善,臃肿,参考,补充,重构,最终形成了一个比较完善的Http工具类。这些都是踩过坑才会慢慢考虑到,逐渐完善的,或许还不够完善不够规范,但是突然发现Spring已经给我们提供了这样的工具类RestTemplate,以上说的功能一个不少,果然出于真实践。

RestTemplateSpring 3.0 就有了,它不是HttpClientHttpConnection的替代品,而是基于这写Http请求框架二次封装简单易用的工具类。它会替你屏蔽底层枯燥重复的Http请求封装,向上提供一个功能齐全强大的Http工具。Spring真正吸引人的不仅仅是一个java框架这么简单,它会站在我们的立场考虑,充分考虑到我们的需求,最终给我们提供最简单易用的一套解决方法。

举几个简单的例子:

  • 简单Get请求,获取状态码,获取body体
@Test
public void testGet() {
    ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://www.baidu.com", String.class);
    System.out.println("statusCode : " + responseEntity.getStatusCodeValue());
    System.out.println("body : " + responseEntity.getBody());
    System.out.println("body : " + responseEntity.toString());
}
  • 获取字节流
@Test
public void testGetByteBody() {
    ResponseEntity<byte[]> responseEntity = restTemplate.getForEntity("http://192.168.24.119/downlaod.jpg", byte[].class);
    System.out.println("statusCode : " + responseEntity.getStatusCodeValue());
    System.out.println("body : " + Arrays.toString(responseEntity.getBody()));
}
  • 自定义请求头,获取想要的Java实体
@Test
public void testPostWithJsonObject() {
    // add jsonConvert
    restTemplate.getMessageConverters().add(new FastJsonHttpMessageConverter());

    Map<String, String> postBody = new HashMap<>();
    postBody.put("username","1");
    postBody.put("password","12312");

    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.add(HttpHeaders.CONTENT_TYPE, "application/json");
    HttpEntity<Map<String,String>> httpRequest = new HttpEntity<>(postBody, httpHeaders);

    ResponseEntity<byte[]> responseEntity = restTemplate.postForEntity("http://192.168.24.119/login", httpRequest, byte[].class);
    System.out.println("statusCode : " + responseEntity.getStatusCodeValue());
    System.out.println("body : " + new String(responseEntity.getBody()));
}
  • 自定义选择Http请求框架(默认httpConnection)
@Bean
public ClientHttpRequestFactory getClientHttpRequestFactory(HttpClientBuilder httpClientBuilder) {
    ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClientBuilder.build());
    return requestFactory;
}

  • 同Spring MVC 实体转化MessageConvert配置
@Bean
public RestTemplate getRestTemplate(ClientHttpRequestFactory requestFactory) {
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.setRequestFactory(requestFactory);
    restTemplate.setMessageConverters(Arrays.<HttpMessageConverter<?>>asList(
            new StringHttpMessageConverter(StandardCharsets.UTF_8),
            new ByteArrayHttpMessageConverter()));
    return restTemplate;
}
  • 面向切面请求的filter,你可以在请求前和请求后做些事
restTemplate.getInterceptors().add((request, bytesBody, execution)->{
    return execution.execute(request, bytesBody);
});
  • 自定义异常处理机制
restTemplate.setErrorHandler(new ResponseErrorHandler() {
    @Override
    public boolean hasError(ClientHttpResponse response) throws IOException {
        return false;
    }

    @Override
    public void handleError(ClientHttpResponse response) throws IOException {
    }
});

配置

RestTemplate实例仅需要配置ClientHttpRequestFactory

配置HttpClientBuilder请求框架

@Bean
public HttpClientBuilder getHttpClientBuilder() throws KeyManagementException, NoSuchAlgorithmException {
    HttpClientBuilder consumer = HttpClients.custom();
    PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(RegistryBuilder.<ConnectionSocketFactory>create()
            .register("https", new SSLConnectionSocketFactory(SSLContextBuilder.create().build()))
            .register("http", new PlainConnectionSocketFactory())
            .build());
    consumer.setConnectionManager(poolingHttpClientConnectionManager);
    return consumer;
}

配置ClientHttpRequestFactory

@Bean
public ClientHttpRequestFactory getClientHttpRequestFactory(HttpClientBuilder httpClientBuilder) {
    ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClientBuilder.build());
    return requestFactory;
}

配置RestTemplate

@Bean
public RestTemplate getRestTemplate(ClientHttpRequestFactory requestFactory) {
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.setRequestFactory(requestFactory);
    restTemplate.setMessageConverters(Arrays.<HttpMessageConverter<?>>asList(
            new StringHttpMessageConverter(StandardCharsets.UTF_8),
            new ByteArrayHttpMessageConverter()));
    return restTemplate;
}

完毕

简单用法

restTemplate使用方法比较简单,这里举几个比较典型的例子

  • restTemplate.execute(Url, HttpMethod, RequestCallback, ResponseExtractor)

最基本最全的执行方法。第一个参数Url简明旨意;第二个参数Httpmethod请求方法;第三个参数RequestCallback是一个请求前的拦截器,在这里可以对请求头,请求体做出自定义的操作;第四个参数ResponseExtractor是请求执行后的拦截器,或者说是一个提取器,自定义转化并返回一个结果。

该方法的返回值就是ResponseExtractor的返回值。

  • restTemplate.exchange(Url, HttpMethod, HttpEntity, Type, uriVars...)

restTemplate.execute上封装,第三个参数HttpEntity可以设置headersbody,它实现的功能也是在RequestCallback基础上实现的;第四个参数Type代表你希望接收一个什么样的返回值(当然,你需要有一个自定义实现的ResponseExtractor, 也就是MessageConvert);第五个参数为url上变量值的替换具体值。

该方法返回一个ResponseEntity<T>类型的返回值,其中T就是第三个参数对应的返回类型,可以通过getBody获取,除此之外ResponseEntity还能获得状态码,headers等信息

  • restTemplate.postForEntity(URL,Request, Type, uriVars...)

进一步封装,将请求方法写到方法名上

  • restTemplate.postForObject(URL,Request, Type, uriVars...)

再封装,如果你只关心值,restTemplate.postForObject可以让你直接获取你想要的值。它的返回值类型直接就是第三个参数Type的值

  • restTemplate.postForLocation(Url,Request)

postForLocation方法是另一种用法,它针对post请求,返回的状态码为302的请求,获取其headerLocation的值

总结

总结来说,关于RestTemplate从配置到使用来说是比较简单的,看着方法就能猜出来其使用的途径,但是又包装的恰到好处,各个设计模式用的也非常6,称之为规范一点都不过分。

猜你喜欢

转载自blog.csdn.net/weixin_33769125/article/details/87516529