Http客户端(发起http请求)
在Java的世界中,Http客户端之前一直是Apache家的HttpClient占据主导,但是由于此包较为庞大,API又比较难用,因此并不使用很多场景。而新兴的OkHttp、Jodd-http固然好用,但是面对一些场景时,学习成本还是有一些的。很多时候,我们想追求轻量级的Http客户端,并且追求简单易用。而JDK自带的HttpUrlConnection可以满足大部分需求。
总结,http客户端有几种:
- JDK自带的HttpURLConnection
- Apache HttpComponents
- OkHttp
- Jodd-http
RestTemplate
RestTemplate只对其他的HTTP客户端进行了封装,本身并没有实现HTTP相关的基础功能。其底层实现是可以配置切换的。
HttpAccessor
RestTemplate有一个非常重要的类叫做HttpAccessor,可以理解为HTTP的基础类
从源码中我们可以看出:
- RestTemplate 支持至少三种HTTP客户端库。
- SimpleClientHttpRequestFactory。对应的HTTP库是java JDK自带的HttpURLConnection。
- HttpComponentsAsyncClientHttpRequestFactory。对应的HTTP库是Apache HttpComponents。
- OkHttp3ClientHttpRequestFactory。对应的HTTP库是OkHttp
- java JDK自带的HttpURLConnection是默认的底层HTTP实现客户端
- SimpleClientHttpRequestFactory,即java JDK自带的HttpURLConnection不支持HTTP协议的Patch方法,如果希望使用Patch方法,需要将底层HTTP客户端实现切换为Apache HttpComponents 或 OkHttp
- 可以通过设置setRequestFactory方法,来切换RestTemplate的底层HTTP客户端实现类库。
底层实现切换方法
OkHttp 优于 Apache HttpComponents、Apache HttpComponents优于HttpURLConnection,可切换为okHTTP。
- 切换为okHTTP
首先引入okHTTP的依赖
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.7.2</version>
</dependency>
如果是spring 环境下通过如下方式使用OkHttp3ClientHttpRequestFactory初始化RestTemplate bean对象。
@Configuration
public class ContextConfig {
@Bean("OKHttp3")
public RestTemplate OKHttp3RestTemplate(){
RestTemplate restTemplate = new RestTemplate(new OkHttp3ClientHttpRequestFactory());
return restTemplate;
}
}
如果是非Spring环境,直接new RestTemplate(new OkHttp3ClientHttpRequestFactory())之后使用就可以了。
- 切换为Apache HttpComponents
引入依赖:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.12</version>
</dependency>
使用HttpComponentsClientHttpRequestFactory初始化RestTemplate bean对象
@Bean("httpClient")
public RestTemplate httpClientRestTemplate(){
RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory());
return restTemplate;
}
如果是非Spring环境,直接new RestTemplate(new HttpComponentsClientHttpRequestFactory())之后使用就可以了。
配置RestTemplate访问细节,例如访问超时、get请求支持body数据
@EnableConfigurationProperties(value = {HttpClientProperties.class})
@Configuration
public class RestTemplateConfig {
@Autowired
@Lazy
private HttpClientProperties httpClientProperties;
@Bean
public RestTemplate restTemplate1() {
RestTemplate restTemplate = new RestTemplate(httpRequestFactory1());
return restTemplate;
}
@Bean
public ClientHttpRequestFactory httpRequestFactory1() {
return new HttpComponentsClientHttpRequestCRMFactory(httpClient1());
}
@Bean
public HttpClient httpClient1() {
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry);
HttpClientProperties.PoolProperties poolProperties = this.httpClientProperties.getPool();
connectionManager.setMaxTotal(poolProperties.getMaxTotal());
connectionManager.setDefaultMaxPerRoute(poolProperties.getDefaultMaxPerRoute());
connectionManager.setValidateAfterInactivity(poolProperties.getValidateAfterInactivity());
RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(httpClientProperties.getSocketTimeout()) //服务器返回数据(response)的时间,超过抛出read timeout
.setConnectTimeout(httpClientProperties.getConnectTimeout()) //连接上服务器(握手成功)的时间,超出抛出connect timeout
.setConnectionRequestTimeout(httpClientProperties.getConnectionRequestTimeout())//从连接池中获取连接的超时时间,超时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
.build();
return HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(connectionManager)
.build();
}
/**
* 支持GET请求发送BODY
*/
private static class HttpComponentsClientHttpRequestCRMFactory extends HttpComponentsClientHttpRequestFactory {
public HttpComponentsClientHttpRequestCRMFactory(HttpClient httpClient) {
super(httpClient);
}
@Override
protected HttpUriRequest createHttpUriRequest(HttpMethod httpMethod, URI uri) {
if (httpMethod == HttpMethod.GET) {
return new HttpGetRequestForBody(uri);
}
return super.createHttpUriRequest(httpMethod, uri);
}
}
private static class HttpGetRequestForBody extends HttpEntityEnclosingRequestBase {
public HttpGetRequestForBody(final URI uri) {
super.setURI(uri);
}
@Override
public String getMethod() {
return HttpMethod.GET.name();
}
}
}
RestTemplate类中的方法
发起请求
Hutool-http(HttpUtil)
Hutool针对Http请求做了一层封装,基于JDK的HttpUrlConnection封装完成,完整支持https、代理、文件上传、Cookie记忆。
Hutool-http的核心集中在两个类:HttpRequest、HttpResponse,针对大部分情境,封装了HttpUtil工具类。