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这种思想。
欢迎大家讨论学习,本人能力有限,也是摸索探究的,有不对的地方欢迎指正。