1. HTTP 代理
HTTP 代理是位于服务端和客户端之间的中间实体,在各个端点之间来回传送HTTP报文
按照用途分为:
- 内容过滤
- 科学上网
- Web缓存。维护服务器常用文档的一个副本,增加客户端的访问速度
- 反向代理。反向代理可以接收发给服务器的真实请求,然后按需交给真实的服务器,类似路由的功能
按照代理对客户端的可见性分为:
- 透明代理
- 非透明代理
2. 连接代理为何要用绝对路径
早期的 HTTP 设计中,客户端只会与单个服务器进行通信,所以一旦 TCP 连接建立起来以后,只需要相对路径。
但代理就有问题,客户端首先和代理建立 TCP 连接,但由于传递的请求头中使用相对路径,代理就不知道使用什么 IP 和 端口来向远端的服务器建立 TCP 连接。所以,对于早期的 HTTP 1.0,强制客户端发给代理时使用完整路径,如
GET http://www.douban.com/ HTTP /1.0
较新的 HTTP 1.1 则规定了必须包含 Host 头部。所以对于 HTTP 1.1 的代理来说,完整 URL 不是必须的。但由于网络上还有大量旧版代理,Host 头部代理或许根本不识别,所以现在浏览器在使用代理时,还是会使用完整 URL
测试如下
[1]:
$nc -lvp 8000
$curl l0calhost:8000
nc >>>
listening on [any] 8000 ...
connect to [127.0.0.1] from localhost [127.0.0.1] 34456
GET / HTTP/1.1
Host: localhost:8000
User-Agent: curl/7.47.0
Accept: */*
[2]:
$ nc -lvp 8088
$curl --proxy localhost:8088 l0calhost:8000
nc >>>
listening on [any] 8088 ...
connect to [127.0.0.1] from localhost [127.0.0.1] 47468
GET http://localhost:8000/ HTTP/1.1
Host: localhost:8000
User-Agent: curl/7.47.0
Accept: */*
Proxy-Connection: Keep-Alive
比较会发现
向代理发送完整的绝对路径 URL。而在普通情况下只会发送相对路径,不需要主机名。
用 Proxy-Connection 头部代替 Connection 头部发送给代理服务器
3. 为什么要用 Proxy-Connection 头部
Connection 头部是为了减少建立 TCP 连接的次数,复用连接产生的。默认 HTTP 1.1 是 Keepalive,但 1.0 的代理则不识别此头部。对于不认识的头部,代理会直接转发,以保持向后兼容性。
假如 Connection: Keep-alive 发给了代理,代理不识别转发给了服务器,而恰巧服务器识别此头部,便会出现严重问题。服务器和浏览器都保持连接,而代理则中断了连接。
为解决这个问题,出现了一个新的头部 Proxy-Connection。如果 1.1 的代理,代理会改写为 Connection 头部。如果 1.0 的代理,那么会直接转发此头部,服务器发现 Proxy-Connection 后,就会采用非长连接的方式。
4. 服务器不一定支持绝对路径的URL
当客户端比如浏览器认为自己在向一个代理服务器发送HTTP请求时,会在请求行中使用绝对路径的URL,如果它认为自己在向目标服务器直接发送请求时,则请求行中只会包含相对路径的URL(完整URL的path部分)。
这是遵循了RFC2616(5.1.2小节)标准的规定。遵照标准,服务器必须能正确解析这两种形式的请求行,但是有些服务器不能正确解析请求行中包含绝对路径的情况,会返回HTTP/4XX或者HTTP/5XX错误