HttpClient4.5 入门

引言

本文主要记录如何构建HttpClient(4.5.x) 和 入门使用.

参考官方文档
http://hc.apache.org/httpcomponents-client-4.5.x/current/tutorial/html/

1. HttpClient构建

1.1 关于HttpClinet

在构建之前, 先大致了解一下HttpClient类
在这里插入图片描述
HttpClient子类

  • DecompressingHttpClient: 装饰器类(已弃用),支持解压缩逻辑,可用RequestAcceptEncoding/ResponseContentEncoding取代.
  • AutoRetryHttpClient: 装饰器类(已弃用),支持服务异常重试逻辑,可用ServiceUnavailableRetryStrategy取代.
  • CloseableHttpClient: 默认的HttpClient
    • MinimalHttpClient: 简易版HttpClient
    • AbstractHttpClient: 已弃用,文档推荐HttpClientBuilder, 构建InternalHttpClient对象.
    • InternalHttpClient: 默认访问权限, 只能通过HttpClientBuilder构建.

经过上述说明, 4.5.x版本中, 我们只需关心如何通过HttpClientBuilder构建HttpClient即可.

此外,HttpClient还提供了HttpClients作为工厂类, 封装了HttpClientBuilder和MinimalHttpClient构建.

1.2 构建HttpClient(默认)

RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(2000) // 创建Socket超时时间.setConnectTimeout(2000) // 请求响应超时时间.build();CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).build()

2. HttpClient使用入门

2.0 构建URI

// 构建URI 方式1
URI uri = URI.create("http://localhost:8080/hello?user=roylion")// 构建URI 方式2
URI uri = new URIBuilder("http://localhost:8080").setPath("/hello").addParameter("user", "roylion").build();

2.1 Get请求

基础GET请求

    /*** 基础get请求** @param uri     请求路径* @param headers 请求header参数 {@link BasicHeader#BasicHeader(String, String)}* @param reqCfg  请求配置参数* @return 返回响应, 用完必须close()* @throws IOException*/public static CloseableHttpResponse baseGet(URI uri, Header[] headers, RequestConfig reqCfg) throws IOException {final HttpGet httpGet = new HttpGet();httpGet.setURI(uri);httpGet.setHeaders(headers);httpGet.setConfig(reqCfg);return httpClient.execute(httpGet);}

GET - FORM表单提交

   /*** form表单提交* * @param uri      请求路径* @param formData 表单数据列表* @return 响应结果* @throws URISyntaxException* @throws IOException*/public static String getFrom(URI uri, List formData) throws URISyntaxException, IOException {URIBuilder uriBuilder = new URIBuilder(uri);for (NameValuePair nameValuePair : formData) {uriBuilder.addParameter(nameValuePair.getName(), nameValuePair.getValue());}URI finalUri = uriBuilder.build();Header[] headers = new Header[]{new BasicHeader("Content-Type", "application/x-www-form-urlencoded")};try (CloseableHttpResponse resp = baseGet(finalUri, headers, null);) {return toString(resp.getEntity());}}

2.2 Post请求

基础POST请求

   /*** 基础post请求** @param uri        请求路径* @param headers    请求header参数 {@link BasicHeader#BasicHeader(String, String)}* @param reqCfg     请求配置参数* @param httpEntity 请求体对象*                   String(文本, json...) {@link StringEntity}*                   form(表单) {@link UrlEncodedFormEntity}*                   multipartForm(文件, 图片, 文本...) {@link MultipartEntityBuilder#build()}* @return 返回响应, 用完必须close()* @throws IOException*/public static CloseableHttpResponse basePost(URI uri, Header[] headers, RequestConfig reqCfg, HttpEntity httpEntity) throws IOException {HttpPost httpPost = new HttpPost();httpPost.setURI(uri);httpPost.setHeaders(headers);httpPost.setConfig(reqCfg);httpPost.setEntity(httpEntity);return httpClient.execute(httpPost);}

POST - JSON 请求

    /*** post请求, 传递JSON请求体** @param uri      请求路径* @param jsonBody json字符串* @return 返回响应结果* @throws IOException*/public static String postJson(URI uri, String jsonBody) throws IOException {StringEntity body = new StringEntity(jsonBody, ContentType.APPLICATION_JSON);try (CloseableHttpResponse resp = basePost(uri, null, null, body)) {return toString(resp.getEntity());}}

POST - FORM 表单提交

    /*** post请求, 表单提交** @param uri      请求路径* @param formData 表单参数列表* @return 返回响应结果* @throws IOException*/public static String postForm(URI uri, List formData) throws IOException {UrlEncodedFormEntity body = new UrlEncodedFormEntity(formData);try (CloseableHttpResponse resp = basePost(uri, null, null, body)) {return toString(resp.getEntity());}}

POST文件上传

    /*** 上传文件** @param uri         请求路径* @param name        上传文件参数名称* @param inputStream 文件的输入流* @param contentType 文件类型*                    普通文件 {@link ContentType#MULTIPART_FORM_DATA}*                    图片 {@link ContentType#IMAGE_JPEG} {@link ContentType#IMAGE_PNG} ...* @param fileName    上传文件名称* @return* @throws IOException*/public static String postFile(URI uri, String name, InputStream inputStream, ContentType contentType, String fileName) throws IOException {// HttpMultipartMode.RFC6532参数的设定是为避免文件名为中文时乱码MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532);multipartEntityBuilder.addBinaryBody(name, inputStream, contentType, fileName);HttpEntity fileEntity = multipartEntityBuilder.build();try (CloseableHttpResponse resp = basePost(uri, null, null, fileEntity)) {return toString(resp.getEntity());}}

POST多文件上传

   /*** 多文件上传** @param uri      请求路径* @param name     上传文件参数名称* @param fileList 文件列表* @return*/public static String postMultipartFile(URI uri, String name, List fileList) throws IOException {// HttpMultipartMode.RFC6532参数的设定是为避免文件名为中文时乱码MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create().setMode(HttpMultipartMode.RFC6532);for (InputStreamBody inputStreamBody : fileList) {multipartEntityBuilder.addPart(name, inputStreamBody);}HttpEntity fileEntity = multipartEntityBuilder.build();try (CloseableHttpResponse resp = basePost(uri, null, null, fileEntity)) {return toString(resp.getEntity());}s}

3. HttpClient详细配置

		以下配置均参考于HttpClientBuilder#build()方法。// userAgent/*** 获取agent* [system]http.agent* 配置userAgent, 优先级高于system. {@link HttpClientBuilder#setUserAgent(String)}* 禁用默认userAgent. {@link HttpClientBuilder#disableDefaultUserAgent()}*/String userAgentCopy = VersionInfo.getUserAgent("Apache-HttpClient","org.apache.http.client", HttpClients.class);/*** 配置公共域名后缀*  {@link HttpClientBuilder#setPublicSuffixMatcher(PublicSuffixMatcher)}*/PublicSuffixMatcher publicSuffixMatcherCopy = PublicSuffixMatcherLoader.getDefault();// =============================> 连接管理 <============================= ///*** 请求执行器, 发送请求的核心代码*  {@link HttpClientBuilder#setRequestExecutor(HttpRequestExecutor)}*/HttpRequestExecutor requestExecCopy = new HttpRequestExecutor();/*** SslSocket工厂类* [system]https.protocols => String[] supportedProtocols* [system]https.cipherSuites => String[] supportedCipherSuites* {@link HttpClientBuilder#setSSLSocketFactory(LayeredConnectionSocketFactory)}* {@link HttpClientBuilder#setSSLContext(SSLContext)}* {@link HttpClientBuilder#setSSLHostnameVerifier(HostnameVerifier)} 用于SSL连接中主机名的校验,因为SSL是要校验证书的*/LayeredConnectionSocketFactory sslSocketFactoryCopy = new SSLConnectionSocketFactory(SSLContexts.createDefault(),new DefaultHostnameVerifier(publicSuffixMatcherCopy));/*** 连接管理器(分单连接和池化连接)* {@link HttpClientBuilder#setConnectionManager(HttpClientConnectionManager)}** [system]http.keepAlive = true*      => [system]http.maxConnections = {max} => DefaultMaxPerRoute=max; MaxTotal=2*max* {@link HttpClientBuilder#setDnsResolver(DnsResolver)}* {@link HttpClientBuilder#setConnectionTimeToLive(long, TimeUnit)}* {@link HttpClientBuilder#setDefaultSocketConfig(SocketConfig)}* {@link HttpClientBuilder#setDefaultConnectionConfig(ConnectionConfig)}* {@link HttpClientBuilder#setMaxConnTotal(int)}* {@link HttpClientBuilder#setMaxConnPerRoute(int)}*/HttpClientConnectionManager connManagerCopy = new PoolingHttpClientConnectionManager(RegistryBuilder.create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslSocketFactoryCopy).build(),null,null,null,-1,TimeUnit.MILLISECONDS);/*** 连接复用策略 根据'Connection: keep-alive'确认是否需要保持连接* http.keepAlive = false => NoConnectionReuseStrategy.INSTANCE(不复用连接)* {@link HttpClientBuilder#setConnectionReuseStrategy(ConnectionReuseStrategy)}*/ConnectionReuseStrategy reuseStrategyCopy = DefaultClientConnectionReuseStrategy.INSTANCE;/*** keepAlive策略 根据'Keep-Alive: timeout=300'确认连接过期时间* {@link HttpClientBuilder#setKeepAliveStrategy(ConnectionKeepAliveStrategy)}*/ConnectionKeepAliveStrategy keepAliveStrategyCopy = DefaultConnectionKeepAliveStrategy.INSTANCE;// =============================> 权限认证(代理)相关 <============================= ///*** 权限认证策略* {@link HttpClientBuilder#setTargetAuthenticationStrategy(AuthenticationStrategy)}*/AuthenticationStrategy targetAuthStrategyCopy = TargetAuthenticationStrategy.INSTANCE;/*** 代理权限认证策略* {@link HttpClientBuilder#setProxyAuthenticationStrategy(AuthenticationStrategy)}*/AuthenticationStrategy proxyAuthStrategyCopy = ProxyAuthenticationStrategy.INSTANCE;/*** 获取用户Token* {@link HttpClientBuilder#setUserTokenHandler(UserTokenHandler)}*/UserTokenHandler userTokenHandlerCopy = DefaultUserTokenHandler.INSTANCE;/*** 权限认证注册仓库* {@link HttpClientBuilder#setDefaultAuthSchemeRegistry(Lookup)}*/Lookup authSchemeRegistryCopy = RegistryBuilder.create().register(AuthSchemes.BASIC, new BasicSchemeFactory()).register(AuthSchemes.DIGEST, new DigestSchemeFactory()).register(AuthSchemes.NTLM, new NTLMSchemeFactory()).register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory()).register(AuthSchemes.KERBEROS, new KerberosSchemeFactory()).build();/*** 权限认证信息仓库* {@link HttpClientBuilder#setDefaultCredentialsProvider(CredentialsProvider)}*/CredentialsProvider defaultCredentialsProvider = new BasicCredentialsProvider();// =============================> Cookie相关 <============================= ///*** Cookie规格仓库* {@link HttpClientBuilder#setDefaultCookieSpecRegistry(Lookup)}*/Lookup cookieSpecRegistryCopy = CookieSpecRegistries.createDefault(publicSuffixMatcherCopy);/*** Cookie存储仓库* {@link HttpClientBuilder#setDefaultCookieStore(CookieStore)}*/CookieStore defaultCookieStore = new BasicCookieStore();// =============================> 执行器职责链 <============================= ///** 构建执行器职责链* MainClientExec(基础)* => ProtocolExec(添加了HttpProcessor拦截器链)* => RetryExec(请求异常重试机制)* => ServiceUnavailableRetryExec(请求响应异常, 延迟重试机制)* => RedirectExec(支持重定向执行器)* => BackoffStrategyExec(回退降级机制)*/ClientExecChain execChain = new MainClientExec(  // 核心执行器requestExecCopy,connManagerCopy,reuseStrategyCopy,keepAliveStrategyCopy,new ImmutableHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),targetAuthStrategyCopy,proxyAuthStrategyCopy,userTokenHandlerCopy);// =============================> 拦截器 <============================= ///*** 构建HttpProcessor拦截器链** 添加优先级高的拦截器* {@link HttpClientBuilder#addInterceptorFirst(HttpRequestInterceptor)}* {@link HttpClientBuilder#addInterceptorFirst(HttpResponseInterceptor)}*/final HttpProcessorBuilder b = HttpProcessorBuilder.create();b.addAll(new RequestDefaultHeaders(Collections.EMPTY_LIST),new RequestContent(),new RequestTargetHost(),new RequestClientConnControl(),new RequestUserAgent(userAgentCopy),new RequestExpectContinue());/*** 往请求中添加cookie的拦截器* {@link HttpClientBuilder#disableCookieManagement()}*/b.add(new RequestAddCookies());/*** 往请求中配置'Accept-Encoding'的拦截器* {@link HttpClientBuilder#disableContentCompression()}* {@link HttpClientBuilder#setContentDecoderRegistry(Map)}*/b.add(new RequestAcceptEncoding());/*** 权限认证缓存的拦截器* {@link HttpClientBuilder#disableAuthCaching()}*/b.add(new RequestAuthCache());/*** 处理响应中的'Set-Cookie'的拦截器* {@link HttpClientBuilder#disableCookieManagement()}*/b.add(new ResponseProcessCookies());/*** 处理'Content-Encoding'响应首部的拦截器* {@link HttpClientBuilder#disableContentCompression()}* {@link HttpClientBuilder#setContentDecoderRegistry(Map)}*/b.add(new ResponseContentEncoding());/*** 添加优先级低的拦截器* {@link HttpClientBuilder#addInterceptorLast(HttpRequestInterceptor)}* {@link HttpClientBuilder#addInterceptorLast(HttpResponseInterceptor)}*/HttpProcessor httpprocessorCopy = b.build();execChain = new ProtocolExec(execChain, httpprocessorCopy); // 带拦截器职责链的执行器/*** 请求重试机制* {@link HttpClientBuilder#disableAutomaticRetries()}* {@link HttpClientBuilder#setRetryHandler(HttpRequestRetryHandler)}*/HttpRequestRetryHandler retryHandlerCopy = DefaultHttpRequestRetryHandler.INSTANCE;execChain = new RetryExec(execChain, retryHandlerCopy);     // 支持请求异常重试的执行器/*** 可选, 依赖服务不可用, 提供延迟重试机制** {@link HttpClientBuilder#setServiceUnavailableRetryStrategy(ServiceUnavailableRetryStrategy)}*/final ServiceUnavailableRetryStrategy serviceUnavailStrategyCopy = null;if (serviceUnavailStrategyCopy != null) {execChain = new ServiceUnavailableRetryExec(execChain, serviceUnavailStrategyCopy); // 支持响应异常, 延迟重试的执行器}/*** Http路由规划 (代理, 端口解析...)* {@link HttpClientBuilder#setRoutePlanner(HttpRoutePlanner)}* {@link HttpClientBuilder#setSchemePortResolver(SchemePortResolver)}* {@link HttpClientBuilder#setProxy(HttpHost)}*/SchemePortResolver schemePortResolverCopy = DefaultSchemePortResolver.INSTANCE;HttpRoutePlanner routePlannerCopy = new DefaultRoutePlanner(schemePortResolverCopy);/*** 重定向策略* {@link HttpClientBuilder#disableRedirectHandling()}* {@link HttpClientBuilder#setRedirectStrategy(RedirectStrategy)}*/RedirectStrategy redirectStrategyCopy = DefaultRedirectStrategy.INSTANCE;execChain = new RedirectExec(execChain, routePlannerCopy, redirectStrategyCopy); // 支持重定向的执行器/*** 回退(服务降级)机制, 重试是自私的, 当重试造成服务超负载时, 应使用回退机制, 使下游系统不可用, 过一段时间后再自动恢复.* {@link HttpClientBuilder#setConnectionBackoffStrategy(ConnectionBackoffStrategy)}* {@link HttpClientBuilder#setBackoffManager(BackoffManager)}*/if (false) {execChain = new BackoffStrategyExec(execChain, null, null);  // 支持回退降级的执行器}// =============================> 关闭资源 <============================= ///*** 配置关闭HttpClient时资源释放操作* {@link  HttpClientBuilder#addCloseable(Closeable)}* {@link  HttpClientBuilder#setConnectionManagerShared(boolean)}* {@link  HttpClientBuilder#evictExpiredConnections()}* {@link  HttpClientBuilder#evictIdleConnections(long, TimeUnit)}**/List closeablesCopy = new ArrayList(1);// 可选, 设置定时关闭空闲/过期的连接if (false) {final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(connManagerCopy,10, TimeUnit.SECONDS,0, null);closeablesCopy.add(new Closeable() {@Overridepublic void close() throws IOException {connectionEvictor.shutdown();try {connectionEvictor.awaitTermination(1L, TimeUnit.SECONDS);} catch (final InterruptedException interrupted) {Thread.currentThread().interrupt();}}});// 启动定时关闭空闲/过期的连接connectionEvictor.start();}// 关闭连接管理器closeablesCopy.add(new Closeable() {@Overridepublic void close() throws IOException {connManagerCopy.shutdown();}});new InternalHttpClient(execChain,connManagerCopy,routePlannerCopy,cookieSpecRegistryCopy,authSchemeRegistryCopy,defaultCookieStore,defaultCredentialsProvider,defaultRequestConfig != null ? defaultRequestConfig : RequestConfig.DEFAULT,closeablesCopy);


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部