当前位置: 首页 > news >正文

[Java]_[中级]_[使用okhttp3和HttpClient代理访问外部网络]

场景

  1. Javahttp库常用的有HttpClientOkhttp3, 如果公司有限制网络访问,需要代理才可以访问外网,那么如何使用代理Proxy
<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.13</version>
</dependency><dependency><groupId>com.squareup.okhttp3</groupId><artifactId>okhttp</artifactId><version>3.14.9</version>
</dependency>

说明

  1. 从性能方面来说,Okhttp3更出色一点。因为从我本机运行两个库的访问, Okhttp3会快一些。

  2. 从易用性来说,Ohttp3更好。OkHttpClient只需要在Builder里调用proxy(Proxy)传递一个Proxy对象之后即可。之后访问其他外网,就直接创建外网的Request即可,非常方便。 代理和非代理都用统一的方法。

    OkHttpClient.Builder builder = client.newBuilder();
    builder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(hostName, Integer.parseInt(hostPort))));...
    Response response = getClient().newCall(request).execute()
    
  3. HttpClient访问[1]则需要创建两个对象: 需要访问的主机HttpHost和URL里的请求路径和查询参数的HttpGet对象。 每次请求都需要传递这两个参数。而如果非代理的话,就需要调用另外的重载方法。

     HttpHost target = HttpHost.create(hostUrl);
    HttpGet request = new HttpGet("/user?name=xxx");
    //  HttpGet httpGet = new HttpGet(hostUrl); // 非代理...
    httpClient.execute(target, request) // 代理
    // httpClient.execute(httpGet); // 非代理
    
  4. 注意,出于创建Client比较废资源,okhttp3还是HttpClient官方都是推荐创建单例的OkHttpClientHttpClient对象来使用。对于CloseableHttpClient在使用完之后还需要调用close()关闭。OkHttpClient官方例子也没有调用销毁方法。

  5. 从源码设计上来说,Okhttp3在发送数据时,使用了自带的线程池,我们想用自己的线程池代替都不行。这个对某些线程数有严格限制的程序(Linux)非常不友好,甚至不能用,因为它的线程不受宿主程序控制。

    // 在类 RealConnectionPool里有这段代码
    static {executor = new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue(), Util.threadFactory("OkHttp ConnectionPool", true));
    }
    

例子

  1. 以下是使用okhttp3HttpClient的目前最佳做法.

OkHttpClientCaller


import Pair;
import StringUtils;
import HttpHelper;
import okhttp3.*;
import org.apache.log4j.Logger;import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.Map;public class OkHttpClientCaller {private static Logger logger = Logger.getLogger(OkHttpClientCaller.class);private static OkHttpClient client;public static void newClient(){OkHttpClient.Builder builder = new OkHttpClient().newBuilder();client = builder.cookieJar(new LocalCookieJar()).build();}public static void setProxy(String hostName,String hostPort){Proxy proxy = client.proxy();if(StringUtils.isEmpty(hostName,hostPort)){if(proxy != null) {client.newBuilder().proxy(null).cookieJar(new LocalCookieJar()).build();}}else{if(proxy == null){OkHttpClient.Builder builder = client.newBuilder();builder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(hostName, Integer.parseInt(hostPort))));client = builder.cookieJar(new LocalCookieJar()).build();}}}public static OkHttpClient getClient(){return client;}public static Pair<Boolean,String> doGet(Map<String,String> hostHeaders,String hostUrl){Request.Builder builder = new Request.Builder().url(hostUrl);HttpHelper.buildRequestHeader(builder,hostHeaders);Request request = builder.get().build();try (Response response = getClient().newCall(request).execute()) {return new Pair<>((response.code() == 200), response.body().string());} catch (Exception e) {logger.error(e.getMessage());}return new Pair<>(false,"");}/**** @param apiUrl* @param apiHeaders* @param contentType "application/x-www-form-urlencoded" "application/json"* @param content* @return*/public static Pair<Boolean,String> doPost(String apiUrl,Map<String,String> apiHeaders,String contentType,String content){// HeaderRequest.Builder builder = new Request.Builder().url(apiUrl);HttpHelper.buildRequestHeader(builder,apiHeaders);MediaType mediaType = MediaType.parse(contentType);RequestBody body = RequestBody.create(mediaType,content);// Posttry(Response response = getClient().newCall(builder.post(body).build()).execute()){return new Pair<>((response.code() == 200), response.body().string());} catch (IOException e) {logger.error(e.getMessage());}return new Pair<>(false,"");}public static Pair<Boolean,String> doPostFormData(String apiUrl,Map<String,String> apiHeaders,String content){return doPost(apiUrl,apiHeaders,"application/x-www-form-urlencoded",content);}public static Pair<Boolean,String> doPostJsonData(String apiUrl,Map<String,String> apiHeaders,String content){return doPost(apiUrl,apiHeaders,"application/json",content);}
}

HttpClientCaller


import Pair;
import StringUtils;
import RequestUtils;
import HttpHelper;
import org.apache.http.HttpHost;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;import static RequestUtils.getPathAndQueryParam;
import static RequestUtils.getPort;public class HttpClientCaller {private static Logger logger = Logger.getLogger(HttpClientCaller.class);private static CloseableHttpClient httpClient;private static RequestConfig requestConfig;//传输超时时间, 10秒private static int socketTimeout = 10000;//建立连接超时时间,默认10秒private static int connectTimeout = 5000;//获取连接超时时间,10秒private static int connectRequest = 5000;private static HttpHost proxy = null;private static HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {@Overridepublic boolean retryRequest(IOException exception,int executionCount, HttpContext context) {return false;}};public static CloseableHttpClient createClientAttr(HttpClientBuilder builder){return builder.setRetryHandler(myRetryHandler).setMaxConnPerRoute(2).setMaxConnTotal(2).build();}public static void newClient() {// setMaxConnTotal是连接池中可用的总最大连接数。setMaxConnPerRoute是限制到单个端口或url的连接总数。httpClient = createClientAttr(HttpClients.custom());//根据默认超时限制初始化requestConfigrequestConfig = getCommonRequestConfigBuilder().build();}public static RequestConfig.Builder getCommonRequestConfigBuilder(){RequestConfig.Builder builder = RequestConfig.custom().setConnectionRequestTimeout(connectRequest).setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout);return builder;}/*** 不行: https://blog.csdn.net/woshirongshaolin/article/details/126992654* @return*/public static SSLConnectionSocketFactory createSSLFactory(){//使用 loadTrustMaterial() 方法实现一个信任策略,信任所有证书try {SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {// 信任所有public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {return true;}}).build();//NoopHostnameVerifier类:  作为主机名验证工具,实质上关闭了主机名验证,它接受任何//有效的SSL会话并匹配到目标主机。HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);return sslsf;} catch (NoSuchAlgorithmException e) {logger.error(e.getMessage());} catch (KeyManagementException e) {logger.error(e.getMessage());} catch (KeyStoreException e) {logger.error(e.getMessage());}return null;}/**** @param hostName* @param port*/public static void setProxy(String hostName,String port){// 不支持// https://github.com/apache/httpcomponents-client/blob/4.5.x/httpclient/src/examples/org/apache/http/examples/client/ClientExecuteProxy.javaif(StringUtils.isEmpty(hostName,port)){if(proxy != null)requestConfig = getCommonRequestConfigBuilder().setProxy(null).build();}else{if(proxy == null){closeClient();SSLConnectionSocketFactory sslFactory = createSSLFactory();if(sslFactory != null)httpClient = createClientAttr(HttpClients.custom().setSSLSocketFactory(sslFactory));proxy = new HttpHost(hostName, Integer.parseInt(port));requestConfig = getCommonRequestConfigBuilder().setProxy(proxy).build();}}}public static void closeClient(){try {if(httpClient != null)httpClient.close();httpClient = null;} catch (Exception e) {e.printStackTrace();}}public static RequestConfig getRequestConfig(){return requestConfig;}public static CloseableHttpClient getClient(){return httpClient;}public static Pair<Boolean,String> doGet(Map<String,String> hostHeaders, String hostUrl){if(proxy != null){URL url = RequestUtils.getUrlOrNull(hostUrl);HttpHost target = new HttpHost(url.getHost(), getPort(url),url.getProtocol());HttpGet request = new HttpGet(getPathAndQueryParam(url));request.setConfig(requestConfig);HttpHelper.buildRequestHeader(request,hostHeaders);try(CloseableHttpResponse response = httpClient.execute(target, request);){return new Pair<>((response.getStatusLine().getStatusCode() == 200),EntityUtils.toString(response.getEntity(), "utf-8"));}catch ( IOException e){e.printStackTrace();}}else{HttpGet httpGet = new HttpGet(hostUrl);httpGet.setConfig(requestConfig);HttpHelper.buildRequestHeader(httpGet,hostHeaders);try(CloseableHttpResponse response = httpClient.execute(httpGet);){return new Pair<>((response.getStatusLine().getStatusCode() == 200),EntityUtils.toString(response.getEntity(), "utf-8"));}catch ( IOException e){e.printStackTrace();}}return new Pair<>(false,"");}public static Pair<Boolean,String> doPost(String apiUrl,Map<String,String> apiHeaders,String contentType,String content) {if(proxy != null){URL url = RequestUtils.getUrlOrNull(apiUrl);HttpHost target = new HttpHost(url.getHost(), getPort(url),url.getProtocol());HttpPost post = new HttpPost(getPathAndQueryParam(url));HttpHelper.buildRequestHeader(post,apiHeaders);if(post.getFirstHeader("Content-Type") == null)post.addHeader("Content-Type",contentType);StringEntity postEntity = new StringEntity(content, "UTF-8");post.setEntity(postEntity);post.setConfig(requestConfig);try(CloseableHttpResponse response = httpClient.execute(target,post)){return new Pair<>((response.getStatusLine().getStatusCode() == 200),EntityUtils.toString(response.getEntity(), "utf-8"));} catch (IOException e) {logger.warn(e.getMessage());}}else{HttpPost post = new HttpPost(apiUrl);HttpHelper.buildRequestHeader(post,apiHeaders);if(post.getFirstHeader("Content-Type") == null)post.addHeader("Content-Type",contentType);StringEntity postEntity = new StringEntity(content, "UTF-8");post.setEntity(postEntity);post.setConfig(requestConfig);try(CloseableHttpResponse response = httpClient.execute(post)){return new Pair<>((response.getStatusLine().getStatusCode() == 200),EntityUtils.toString(response.getEntity(), "utf-8"));} catch (IOException e) {logger.warn(e.getMessage());}}return  new Pair<>(false,"");}public static Pair<Boolean,String> doPostFormData(String apiUrl,Map<String,String> apiHeaders,String content){return doPost(apiUrl,apiHeaders,"application/x-www-form-urlencoded; charset=UTF-8",content);}public static Pair<Boolean,String> doPostJsonData(String apiUrl,Map<String,String> apiHeaders,String content){return doPost(apiUrl,apiHeaders,"application/json; charset=UTF-8",content);}
}

HttpHelper


import okhttp3.Request;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.message.AbstractHttpMessage;import java.util.Map;public class HttpHelper {public static void buildRequestHeader(AbstractHttpMessage builder, Map<String,String> values){for (Map.Entry<String,String> keyValue:values.entrySet()) {builder.addHeader(keyValue.getKey(),keyValue.getValue());}}public static void buildRequestHeader(Request.Builder builder,Map<String,String> values){for (Map.Entry<String,String> keyValue:values.entrySet()) {builder.addHeader(keyValue.getKey(),keyValue.getValue());}}public static String toFormData(Map<String,String> params){StringBuilder sb = new StringBuilder();for (Map.Entry<String,String> keyValue: params.entrySet())sb.append(keyValue.getKey()).append("=").append(keyValue.getValue()).append("&");if(sb.length() > 0)return sb.substring(0,sb.length()-1);return "";}
}

RequestUtils

import java.net.MalformedURLException;
import java.net.URL;public class RequestUtils {/**** @param url* @return URL or null*/public static URL getUrlOrNull(String url){try {return new URL(url);} catch (MalformedURLException e) {e.printStackTrace();}return null;}public static int getPort(URL url){int port = url.getPort();return (port == -1)?url.getDefaultPort():port;}public static String getPathAndQueryParam(URL url){String path = url.getPath();String query = url.getQuery();if(query == null)return path;return String.format("%s?%s",path,query);}
}

运行

OkHttpClientCaller.newClient();
OkHttpClientCaller.setProxy("127.0.0.1","1283");
Pair<Boolean, String> pp = OkHttpClientCaller.doGet(headers, "https://www.bing.com");
if(pp.k)logger.info(pp.v);OkHttpClientCaller.closeClient();

参考

  1. httpcomponents-client/httpclient/src/examples/org/apache/http/examples/client/ClientExecuteProxy.java

  2. Httpclient3.1指定tlsv1.2协议访问https

  3. java http请求设置代理 Proxy_java

  4. RestTemplate发起HTTPS请求Unsupported or unrecognized SSL message

  5. HttpClient访问不安全的https链接报错:SSLHandshakeException

  6. httpclient信任所有证书解决SSLException:Unrecognized SSL message

  7. Java URI getQuery()方法及示例

http://www.lryc.cn/news/163730.html

相关文章:

  • ubuntu 20.04 docker 安装 mysql
  • C++在C语言基础上的优化
  • 分享一个python实验室设备预约管理系统 实验室设备维修系统源码 lw 调试
  • 兵者多诡(HCTF2016)
  • 【JAVA-Day04】Java关键字和示例:深入了解常用关键字的用法
  • Android请求网络报错:not permitted by network security policy
  • python报错:ImportError: urllib3 v2.0 only supports OpenSSL 1.1.1
  • 如何使用adb command来设置cpu频率和核数
  • 236. 二叉树的最近公共祖先
  • Git常见问题:git pull 和 git pull --rebase二者区别
  • 关于HarmonyOS元服务的主题演讲与合作签约
  • cache 学习
  • SSM - Springboot - MyBatis-Plus 全栈体系(六)
  • 【Flutter】引入网络图片时,提示:Failed host lookup: ‘[图片host]‘
  • Python基础教程:索引和切片
  • JVM基础面试题
  • 蓝桥杯官网填空题(平方末尾)
  • 深入探究数据结构与算法:构建强大编程基础
  • Android 自定义View之圆形进度条
  • 力扣(LeetCode)算法_C++——字母异位词分组
  • 【LeetCode-中等题】59. 螺旋矩阵 II
  • 错误: 找不到或无法加载主类 Main
  • 【云原生】Kubeadmin安装k8s集群
  • Java:Springboot和React中枚举值(数据字典)的使用
  • git撤回 不小心 commit 进去的文件
  • qt之movetothread理解
  • 深入剖析:垃圾回收你真的了解吗?
  • ue5 物理场的应用
  • 移动零00
  • go初识iris框架(四) -框架设置操作