HttpClient--代理支持

先看下这篇文章

HttpClient4.5.3设置代理(Proxy)访问目标地址 - CSDN博客​blog.csdn.net/ly6cyh/article/details/

数据采集,爬虫等可能需要用到代理IP来访问目标地址,以下代码为HttpClient4.5.3使用代理(Proxy)访问目标地址;

//设置代理IP、端口、协议(请分别替换) HttpHost proxy = new HttpHost("你的代理的IP", 8080, "http"); //把代理设置到请求配置 RequestConfig defaultRequestConfig = RequestConfig.custom().setProxy(proxy).build(); //实例化CloseableHttpClient对象 CloseableHttpClient httpclient = HttpClients.custom() .setDefaultRequestConfig(defaultRequestConfig) .build(); //访问目标地址 HttpGet httpGet = new HttpGet(""); //请求返回 CloseableHttpResponse httpResp = httpclient.execute(httpGet); try { int statusCode = httpResp.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_OK) { System.out.println("成功"); } } catch (Exception e) { } finally { httpResp.close(); }

首先我们先介绍下,什么是Http的代理?

HTTP 代理原理及实现(一) | JerryQu 的小站​imququ.com/post/web-proxy.html

摘录如下:

HTTP 代理存在两种形式,分别简单介绍如下:

第一种是 RFC 7230 - HTTP/1.1: Message Syntax and Routing(即修订后的 RFC 2616,HTTP/1.1 协议的第一部分)描述的普通代理。这种代理扮演的是「中间人」角色,对于连接到它的客户端来说,它是服务端;对于要连接的服务端来说,它是客户端。它就负责在两端之间来回传送 HTTP 报文。

第二种是 Tunneling TCP based protocols through Web proxy servers(通过 Web 代理服务器用隧道方式传输基于 TCP 的协议)描述的隧道代理。它通过 HTTP 协议正文部分(Body)完成通讯,以 HTTP 的方式实现任意基于 TCP 的应用层协议代理。这种代理使用 HTTP 的 CONNECT 方法建立连接,但 CONNECT 最开始并不是 RFC 2616 - HTTP/1.1 的一部分,直到 2014 年发布的 HTTP/1.1 修订版中,才增加了对 CONNECT 及隧道代理的描述,详见 RFC 7231 - HTTP/1.1: Semantics and Content。实际上这种代理早就被广泛实现。

本文描述的第一种代理,对应《HTTP 权威指南》一书中第六章「代理」;第二种代理,对应第八章「集成点:网关、隧道及中继」中的 8.5 小节「隧道」。

普通代理

第一种 Web 代理原理特别简单:

HTTP 客户端向代理发送请求报文,代理服务器需要正确地处理请求和连接(例如正确处理 Connection: keep-alive),同时向服务器发送请求,并将收到的响应转发给客户端。

下面这张图片来自于《HTTP 权威指南》,直观地展示了上述行为:

假如我通过代理访问 A 网站,对于 A 来说,它会把代理当做客户端,完全察觉不到真正客户端的存在,这实现了隐藏客户端 IP 的目的。当然代理也可以修改 HTTP 请求头部,通过 X-Forwarded-IP 这样的自定义头部告诉服务端真正的客户端 IP。但服务器无法验证这个自定义头部真的是由代理添加,还是客户端修改了请求头,所以从 HTTP 头部字段获取 IP 时,需要格外小心。这部分内容可以参考我之前的《HTTP 请求头中的 X-Forwarded-For》这篇文章。

给浏览器显式的指定代理,需要手动修改浏览器或操作系统相关设置,或者指定 PAC(Proxy Auto-Configuration,自动配置代理)文件自动设置,还有些浏览器支持 WPAD(Web Proxy Autodiscovery Protocol,Web 代理自动发现协议)。显式指定浏览器代理这种方式一般称之为正向代理,浏览器启用正向代理后,会对 HTTP 请求报文做一些修改,来规避老旧代理服务器的一些问题,这部分内容可以参考我之前的《Http 请求头中的 Proxy-Connection》这篇文章。

还有一种情况是访问 A 网站时,实际上访问的是代理,代理收到请求报文后,再向真正提供服务的服务器发起请求,并将响应转发给浏览器。这种情况一般被称之为反向代理,它可以用来隐藏服务器 IP 及端口。一般使用反向代理后,需要通过修改 DNS 让域名解析到代理服务器 IP,这时浏览器无法察觉到真正服务器的存在,当然也就不需要修改配置了。反向代理是 Web 系统最为常见的一种部署方式,例如本博客就是使用 Nginx 的 proxy_pass 功能将浏览器请求转发到背后的 Node.js 服务。

-----------------------

显然HttpClient实现的是第一种代理

那么我们的HttpClient是如何实现第一种代理的呢?

事实上上HttpHost这个代理对象最终被设置到了HttpRoute当中,那最终是如何调用的呢?

我们看到最重要的调用方式是org.apache.http.impl.conn.PoolingHttpClientConnectionManager类当中的connect方法

connect(HttpClientConnection, HttpRoute, int,HttpContext)

的方法;

其实主要是往代理HttpHost对应的代理网络服务上发送了http请求,代理在获知这个请求后,会将请求转发到真正的域名服务器;