HttpURLConnection、HttpClient设置代理Proxy
有如下一种需求,原本A要给C发送请求,但是因为网络原因,需要借助B才能实现,所以由原本的A->C变成了A->B->C。
这种情况,更多的见于内网请求由统一的网关做代理然后转发出去,比如你本地的机器想要对外上网,都是通过运营商给的出口IP也就是公网地址实现的。这种做法就是代理了。
研究了一下针对 HttpURLConnection和HttpClient这两种常见的http请求的代理:
一、HttpURLConnection设置请求代理
贴出一个utils类
具体代码如下:
public class ProxyUtils { public static final String CONTENT_TYPE = "application/x-www-form-urlencoded"; public static String getResultByHttpConnectionProxy(String url, String content, String proxyHost, int proxyPort) { String result = ""; OutputStream outputStream = null; InputStream inputStream = null; try { //设置proxy Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)); URL proxyUrl = new URL(url); //判断是哪种类型的请求 if (url.startsWith("https")) { HttpsURLConnection httpsURLConnection = (HttpsURLConnection) proxyUrl.openConnection(proxy); httpsURLConnection.setRequestProperty("Content-Type", CONTENT_TYPE); //允许写入 httpsURLConnection.setDoInput(true); //允许写出 httpsURLConnection.setDoOutput(true); //请求方法的类型 POST/GET httpsURLConnection.setRequestMethod("POST"); //是否使用缓存 httpsURLConnection.setUseCaches(false); //读取超时 httpsURLConnection.setReadTimeout(15000); //连接超时 httpsURLConnection.setConnectTimeout(15000); //设置SSL httpsURLConnection.setSSLSocketFactory(getSsf()); //设置主机验证程序 httpsURLConnection.setHostnameVerifier((s, sslSession) -> true); outputStream = httpsURLConnection.getOutputStream(); outputStream.write(content.getBytes(StandardCharsets.UTF_8)); outputStream.flush(); inputStream = httpsURLConnection.getInputStream(); } else { HttpURLConnection httpURLConnection = (HttpURLConnection) proxyUrl.openConnection(proxy); httpURLConnection.setRequestProperty("Content-Type", CONTENT_TYPE); httpURLConnection.setDoOutput(true); httpURLConnection.setDoInput(true); httpURLConnection.setRequestMethod("POST"); httpURLConnection.setUseCaches(false); httpURLConnection.setConnectTimeout(15000); httpURLConnection.setReadTimeout(15000); outputStream = httpURLConnection.getOutputStream(); outputStream.write(content.getBytes("UTF-8")); outputStream.flush(); inputStream = httpURLConnection.getInputStream(); } byte[] bytes = read(inputStream, 1024); result = (new String(bytes, "UTF-8")).trim(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (outputStream != null) { outputStream.close(); } if (inputStream != null) { inputStream.close(); } } catch (Exception e) { e.printStackTrace(); } } return result; } public static byte[] read(InputStream inputStream, int bufferSize) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[bufferSize]; for (int num = inputStream.read(buffer); num != -1; num = inputStream.read(buffer)) { baos.write(buffer, 0, num); } baos.flush(); return baos.toByteArray(); } private static SSLSocketFactory getSsf() { SSLContext ctx = null; try { ctx = SSLContext.getInstance("TLS"); ctx.init(new KeyManager[0], new TrustManager[]{new ProxyUtils.DefaultTrustManager()}, new SecureRandom()); } catch (Exception e) { e.printStackTrace(); } assert ctx != null; return ctx.getSocketFactory(); } private static final class DefaultTrustManager implements X509TrustManager { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } }}
上面的代码就是对httpsURLConnection设置了Proxy代理,也就是请求先会发到proxyHost:proxyPort,然后由其代理发到url。
二、HttpClient设置请求代理
贴出一个utils类
具体代码如下:
public class HttpclientUtils { private static final String CONTENT_TYPE = "application/x-www-form-urlencoded"; public static String getResultByProxy(String url, String request, String proxyHost, int proxyPort) throws Exception { String response = null; HttpPost httpPost = null; try { HttpClient httpClient = getHttpClient(url); //设置请求配置类 重点就是在这里添加setProxy 设置代理 RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(15000).setConnectTimeout(15000) .setConnectionRequestTimeout(15000).setProxy(new HttpHost(proxyHost, proxyPort)).build(); httpPost = new HttpPost(url); httpPost.setConfig(requestConfig); httpPost.addHeader("Content-Type", CONTENT_TYPE); httpPost.setEntity(new StringEntity(request, "utf-8")); response = getHttpClientResponse(httpPost, httpClient); } catch (Exception e) { e.printStackTrace(); } finally { if (null != httpPost) { httpPost.releaseConnection(); } } return response; } private static String getHttpClientResponse(HttpPost httpPost, HttpClient httpClient) throws Exception { String result = null; HttpResponse httpResponse = httpClient.execute(httpPost); HttpEntity entity = httpResponse.getEntity(); if (null != entity) { try (InputStream inputStream = entity.getContent()) { byte[] bytes = read(inputStream, 1024); result = new String(bytes, StandardCharsets.UTF_8); } } return result; } private static HttpClient getHttpClient(String url) throws Exception { HttpClient httpClient; String lowerURL = url.toLowerCase(); if (lowerURL.startsWith("https")) { httpClient = createSSLClientDefault(); } else { httpClient = HttpClients.createDefault(); } return httpClient; } private static CloseableHttpClient createSSLClientDefault() throws Exception { SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (chain, authType) -> true).build(); SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, (s, sslSession) -> true); return HttpClients.custom().setSSLSocketFactory(sslsf).build(); } public static byte[] read(InputStream inputStream, int bufferSize) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[bufferSize]; for (int num = inputStream.read(buffer); num != -1; num = inputStream.read(buffer)) { baos.write(buffer, 0, num); } baos.flush(); return baos.toByteArray(); }}
以上就是针对http、https的代理汇总,其实想想,就是通过 Proxy 对象,添加对应的代理地址和端口,实现了一层转发,可以想到nginx、gateway这种思想。
欢迎大家讨论学习,本人能力有限,也是摸索探究的,有不对的地方欢迎指正。
来源地址:https://blog.csdn.net/qq_38653981/article/details/129066422