从技术上讲,代理服务器只是一个接受请求并把这些请求转发到最终目的地或者另一个代理服务器的代理程序。代理服务器的典型应用是实现缓冲和防火墙。
在HTTP这一层次,一个穿过代理服务器的请求和一般的请求没有很大的区别。一般来说,这个请求被送到代理服务器而不是真正的目的地,而且地址被完全记录下来,以便于代理服务器能够找到目标主机。
Java以特殊的系统属性为代理服务器提供支持。你所需要做的就是把http.proxyHost属性设置到代理服务器地址,把http.proxyPort设置到代理服务器端口。例如,假如在地址proxy.mycompany.com:8132有一个代理服务器,以下这段代码使用这个代理服务器配置了Java的HTTP协议:
System.getProperties().setProperty( "http.proxyHost",
"proxy.mycompany.com" );
System.getProperties().setProperty( "http.proxyPort", "8132"
);
对于简单的情况这个支持就够了。但是有些代理,尤其是防火墙,被配置成需要验证,以允许请求通过。在这种情况下,就必须提供验证支持,这就引出了HTTP验证。
HTTP协议支持对资源的保护,所以必须提供一个合适的验证方法来访问这些资源。当一个请求要对这样的资源进行访问,Web服务器会回应一个401(未经授权的)错误码(见RFC2616),在这种情况下,包含了一个指定方案和域的WWW验证报头。
这个方案定义了提供权限的方法。目前指定了两种策略:基本的和摘要的(见RFC2617)。我会把重点放在基本策略上,因为它更普遍也更容易实现,尽管摘要策略更加强大且提供更高的安全性。
域是一个定义相同主机内受保护区间(一组需要保护的资源)的任意串。单一的主机可以有多个域,相同域内的所有资源都共享相同权限——也就是说,如果对给定资源请求的权限是合法的,那么在相同的区域内,对其他资源的任何后来的请求也必须是合法的。
假设你要访问某个Web服务器上“Protected Territory”内的一个受保护资源,那么会应将包含以下报头(假设Web服务器使用的是基本的验证):
WWW-Authenticate: Basic realm="Protected Territory"
你必须重新发出请求,并包括指定了合法用户名和密码的验证报头。如何提取用户名和密码则是应用程序的工作了。例如浏览器通常使用显示主机和域的对话框来要求输入用户名和密码。
验证报头必须以<username>:<password>的形式,提供所使用的验证方案、用户名和密码(一个base64编码串,见RFC2045)。所以,如果用户名是Alladin(阿拉丁),密码是“open sesame(芝麻开门)”,那么要送出的报头就应该是:
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
代理服务器也是这样的,除非代理服务器回应一个407(需要代理服务器验证)错误码和代理服务器验证报头,这个报头是回应一个不包含合法权限的请求的。权限必须在请求的代理服务器验证报头里提供。
代理服务器要在应用程序的配置里设定,用户名和密码也是一样的。使用这个方法,应用程序就不用等待要求必要信息的407错误码,也不用重新发送请求了。