zoukankan      html  css  js  c++  java
  • 工具篇:apachehttpClient 和 jdk11HttpClient的使用

    关注公众号,一起交流,微信搜一搜: 潜行前行

    HttpClient (apache)

    apache HttpClient 是 java项目里 较为常用的组件之一;对接外部服务时,各个商家提供的接口是各式各样的,有自己的要求,因此要定制对应的请求客户端。httpClient是一个不错的选择

    • apache HttpClient 实现了 HTTP 1.0 和 HTTP 1.1。支持 HTTP 全部的方法(GET, POST, PUT, DELETE, HEAD, OPTIONS, and TRACE)
      • GET, POST 的实现是继承 HttpRequestBase,HttpRequestBase 实现 HttpUriRequest,HttpUriRequest 继承 HttpRequest;GET, POST 方法对应 java 类的 HttpGet 和 HttpPost
    • 支持 TLS,SSL 的 HTTPS。支持多线程操作
    • 基于阻塞的 I/0 实现,也就是说使用 HttpClient 的线程会被阻塞
    • 头部信息设置
    HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/app");
    httpPost.addHeader("Accept", "application/json");
    httpPost.addHeader("Content-type","application/json; charset=utf-8");
    
    • 证书信息设置
    private static SSLContext getSslContext() throws Exception {
        //自身私钥
        KeyStore identityKeyStore = KeyStore.getInstance("jks");
        FileInputStream identityKeyStoreFile = new FileInputStream("/root/myServer.jks");
        identityKeyStore.load(identityKeyStoreFile, "password1".toCharArray());
        //服务端信任证书
        KeyStore trustKeyStore = KeyStore.getInstance("jks");
        FileInputStream trustKeyStoreFile = new FileInputStream("/root/trustKeyStore.jks");
        trustKeyStore.load(trustKeyStoreFile, "password".toCharArray());
        //构建SSLContexts
        return SSLContexts.custom()
                .loadKeyMaterial(identityKeyStore, "password1".toCharArray()) // load identity keystore
                .loadTrustMaterial(trustKeyStore, null) // load trust keystore
                .build();
    }
    public static void postWithSSL(String url, String jsonBody) throws Exception {
        SSLContext sslContext = getSslContext();
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
                sslContext, new String[]{"TLSv1.2", "TLSv1.1", "TLSv1"}, null,
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());
        CloseableHttpClient client = HttpClients.custom()
                .setSSLSocketFactory(sslConnectionSocketFactory)
                .build();
        /**
        // HttpClients 产生的 client 都共用相同的证书秘钥
        Registry<ConnectionSocketFactory> socketFactoryRegistry =  RegistryBuilder.<ConnectionSocketFactory>create()
                                 .register("http", PlainConnectionSocketFactory.INSTANCE)
                                 .register("https", new SSLConnectionSocketFactory(sslcontext))
                                 .build(); 
        HttpClients.custom().setConnectionManager(connManager);
        */
        ....
    }
    
    • 缓存 cookie 设置
    //自定义 cookie
    CookieStore cookieStore = new BasicCookieStore();
    BasicClientCookie cookie = new BasicClientCookie("csc", "lwl");
    cookieStore.addCookie(cookie);
    // 从上一次请求获取
    HttpPost httppost = ...
    DefaultHttpClient httpclient = new DefaultHttpClient();
    HttpResponse response = httpclient.execute(httppost);
    CookieStore cookiestore=httpclient.getCookieStore();
    // DefaultHttpClient 使用 cookie
    HttpPost httppost2 = ...
    DefaultHttpClient httpclient2 = new DefaultHttpClient();
    httpclient2.setCookieStore(cookiestore);
    response = httpclient2.execute(httppost2);
    
    • RequestConfig 的使用
    RequestConfig defaultRequestConfig = RequestConfig.custom()
    .setConnectTimeout(5000) 
    .setSocketTimeout(5000)  
    .setConnectionRequestTimeout(5000) 
    .setRedirectsEnabled(true)
    .build();
    //使用
    CloseableHttpClient httpclient = HttpClients.custom()
    .setDefaultRequestConfig(defaultRequestConfig)
    .build();
    
    • HttpEntity 是对《请求或者响应》对象的封装,具体实现类有
      • BasicHttpEntity,InputStreamEntity:操作对象是数据流
      • BufferedHttpEntity:带缓冲区的 HttpEntity,其他HttpEntity的包装类,将内容存入一缓存区 可以重复读
      • FileEntity:文件对应的Entity FileEntity entity = new FileEntity(new File(""), "application/java-achive");
      • StringEntity:字符串 Entity。一般用 json ,text/plain,text/xml 类型的post请求
      • UrlEncodedFormEntity,一般用于 application/x-www-form-urlencoded 类型的post请求
    • HttpContext:它是 Http 请求上下文类,如果是同一个上下文,则两次请求间可以共享这个上线文的信息。虽然 HttpClient 本身就具备维护cookies的功能,但 HttpContext 的好处是在于多个 HttpClient 实例之间可以共享 HttpContext

    一些建议

    • 1 释放资源:读取完响应后,我们需要尽快释放response本身和响应实体本身的流来对资源进行回收
    • 2 有时可能需要多次读取返回的响应内容,将响应内容进行缓冲。最简单的方法是用BufferedHttpEntity 类包装原始实体。这会让原始实体的内容被读入内存缓冲区
    CloseableHttpResponse response = ...
    HttpEntity entity = new BufferedHttpEntity(response.getEntity());
    
    • 3 HttpClient 的线程安全:使用同一个HttpClient的实例即可做到线程安全,因为 HttpClient 内部就有一个池化机制,支持多线程
    • 4 EntityUtils.toString(entity) : 把内容转成字符串

    CloseableHttpClient 是 HttpClient 的子类。mvn 引入

    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.5</version>
    </dependency>
    <dependency>
    	<groupId>org.apache.httpcomponents</groupId>
    	<artifactId>httpmime</artifactId>
    	<version>4.5.5</version>
    </dependency>
    

    HttpClient 的API

    HttpResponse execute(HttpUriRequest request)
    HttpResponse execute(HttpUriRequest request, HttpContext context)
    HttpResponse execute(HttpHost target, HttpRequest request)
    HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context)
    <T> T execute(HttpUriRequest request, ResponseHandler<? extends T> responseHandler)
    <T> T execute(HttpHost target,HttpRequest request, ResponseHandler<? extends T> responseHandler)
    <T> T execute(HttpHost target, HttpRequest request,
                ResponseHandler<? extends T> responseHandler, HttpContext context)
    

    get 请求

    CloseableHttpClient httpclient = HttpClients.createDefault();
    HttpGet httpGet = new HttpGet("http://localhost:8080/content/lwl");
    CloseableHttpResponse  httpResponse = httpClient.execute(httpGet);
    HttpEntity httpEntity = httpResponse.getEntity();
    System.out.println(EntityUtils.toString(httpEntity));// 输出请求结果
    httpResponse.close();
    

    post 请求

    CloseableHttpClient httpclient = HttpClients.createDefault();
    HttpPost httpPost = new HttpPost("https://www.baidu.com");
    ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
    params.add(new BasicNameValuePair("username", "csc"));
    params.add(new BasicNameValuePair("password", "lwl"));
    httpPost.setEntity(new UrlEncodedFormEntity(params));
    CloseableHttpResponse httpResponse = httpClient.execute(httpPost);
    HttpEntity httpEntity = httpResponse.getEntity();
    System.out.println(EntityUtils.toString(httpEntity));// 输出请求结果
    httpResponse.close();
    

    文件上传

    CloseableHttpClient httpClient = HttpClientBuilder.create().build();
    HttpPost httpPost = new HttpPost("http://localhost:8080/lwl/upload");
    
    MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
    File file1 = new File("C:\\Users\\csc\\Desktop\\data.jpg"); // 第一个文件
    multipartEntityBuilder.addBinaryBody("files", file1);
    File file2 = new File("C:\\Users\\csc\\Desktop\\头像.jpg"); // 第二个文件
    // 为避免中文乱码问题,可以对文件名 urlDecode
    multipartEntityBuilder.addBinaryBody("files", file2, ContentType.DEFAULT_BINARY, URLEncoder.encode(file2.getName(), "utf-8"));
    
    // 其它参数 
    multipartEntityBuilder.addTextBody("name", "lwl", ContentType.create("text/plain", Charset.forName("UTF-8"))); 
       
    HttpEntity httpEntity = multipartEntityBuilder.build();
    httpPost.setEntity(httpEntity);
    CloseableHttpResponse response = httpClient.execute(httpPost);
    HttpEntity responseEntity = response.getEntity();
    System.out.println(response.getStatusLine()); 
    response.close();
    

    HttpClient (jdk11)

    java.net.http.HttpClient 是 jdk11 中正式启用的一个 http 工具类(在 jdk9 的时候就已经存在),官方想要取代 HttpURLConnection 和 Apache HttpClient 等比较古老的开发工具

    HttpClient 的API

    //创建一个 HttpClient
    public static Builder newBuilder()
    public static HttpClient newHttpClient() //  HttpClient.newBuilder().build()
    //webSocket协议的请求客户端的构建者
    public WebSocket.Builder newWebSocketBuilder()
    public abstract Optional<CookieHandler> cookieHandler() // 获取 CookieHandler
    public abstract Optional<Duration> connectTimeout()
    public abstract Redirect followRedirects()
    public abstract Optional<ProxySelector> proxy()
    public abstract SSLContext sslContext()
    public abstract Optional<Executor> executor()
    
    • HttpClient.Builder 的 API
    //缓存cookie设置
    public Builder cookieHandler(CookieHandler cookieHandler);
    //连接超时时间
    public Builder connectTimeout(Duration duration);
    // 证书信息设置
    public Builder sslContext(SSLContext sslContext);
    // SSL / TLS / DTLS连接的参数 设置
    public Builder sslParameters(SSLParameters sslParameters);
    //涉及到异步操作用到的 线程池
    public Builder executor(Executor executor);
    // 是否支持重定向 Redirect.SAME_PROTOCOL
    public Builder followRedirects(Redirect policy);
    // 协议版本,HTTP/1.1 还是 HTTP/2
    public Builder version(HttpClient.Version version);
    public Builder priority(int priority);
    //配置代理 
    public Builder proxy(ProxySelector proxySelector);
    //认证 Authenticator.getDefault()
    public Builder authenticator(Authenticator authenticator);
    
    • HttpClient 调用 API
    //阻塞调用
    <T> HttpResponse<T> send(HttpRequest request, HttpResponse.BodyHandler<T> responseBodyHandler)
    //相当于使用了多路复用I/O
    <T> CompletableFuture<HttpResponse<T>> sendAsync(HttpRequest request, BodyHandler<T> responseBodyHandler)
    abstract <T> CompletableFuture<HttpResponse<T>> sendAsync(HttpRequest request, 
    	BodyHandler<T> responseBodyHandler, PushPromiseHandler<T> pushPromiseHandler)
    

    HttpRequest 构建的 API

    对于请求内容可以使用 BodyPublishers 封装的函数生成
    image.png

    HttpResponse 的API

    对于响应的解析读取可以使用 BodyHandlers 或者 BodySubscribers 封装的函数处理
    image.png

    get 请求

    HttpRequest request = HttpRequest.newBuilder(URI.create("http://localhost:8080/content/lwl"))
            .GET()
            .timeout(Duration.ofSeconds(10)) // 设置响应超时时间
            .build();
    HttpClient httpClient = HttpClient.newHttpClient();
    HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    System.out.println(response.body());
    

    post 请求

    String data = .....// json 请求数据
    HttpRequest request = HttpRequest.newBuilder(URI.create("https://www.baidu.com"))
            .POST(HttpRequest.BodyPublishers.ofString(data, Charset.defaultCharset()))
            .header("Content-Type", "application/json") //设置头部信息
            .timeout(Duration.ofSeconds(10)) // 设置响应超时时间
            .build();
    HttpClient httpClient = HttpClient.newHttpClient();
    HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    System.out.println(response.body());
    

    欢迎指正文中错误

    参考文章

  • 相关阅读:
    命令基础
    绑定在表单验证上的应用
    绑定和绑定的各种使用场景
    双向数据绑定
    事件
    委托应用及泛型委托和多播委托
    委托
    LINQ
    反射重要属性方法
    反射基本内容
  • 原文地址:https://www.cnblogs.com/cscw/p/15547769.html
Copyright © 2011-2022 走看看