ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

HttpClient4.5 入门

2021-06-30 21:29:47  阅读:215  来源: 互联网

标签:入门 uri param HttpClientBuilder link HttpClient4.5 new String


引言

本文主要记录如何构建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<NameValuePair> 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<NameValuePair> 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<InputStreamBody> 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.<ConnectionSocketFactory>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<AuthSchemeProvider> authSchemeRegistryCopy = RegistryBuilder.<AuthSchemeProvider>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<CookieSpecProvider> 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<Closeable> closeablesCopy = new ArrayList<Closeable>(1);
        // 可选, 设置定时关闭空闲/过期的连接
        if (false) {
            final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(connManagerCopy,
                    10, TimeUnit.SECONDS,
                    0, null);
            closeablesCopy.add(new Closeable() {
                @Override
                public 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() {
            @Override
            public void close() throws IOException {
                connManagerCopy.shutdown();
            }
        });

        new InternalHttpClient(
                execChain,
                connManagerCopy,
                routePlannerCopy,
                cookieSpecRegistryCopy,
                authSchemeRegistryCopy,
                defaultCookieStore,
                defaultCredentialsProvider,
                defaultRequestConfig != null ? defaultRequestConfig : RequestConfig.DEFAULT,
                closeablesCopy);

标签:入门,uri,param,HttpClientBuilder,link,HttpClient4.5,new,String
来源: https://blog.csdn.net/weixin_39955960/article/details/117919357

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有