1.2 如何发起一个请求
如何发起一个HTTP请求?这个问题似乎既简单又复杂,简单是指当你在浏览器里输入一个URL时,按回车键后这个HTTP请求就发起了,很快你就会看到这个请求的返回结果。复杂是指能否不借助浏览器也能发起请求,这里的“不借助”有两层含义,一是指能不能自己组装一个符合HTTP协议的数据包,二是处理浏览器还有哪些方式也能简单地发起一个HTTP请求。下面就按照这两层含义来解释如何发起一个HTTP请求。
如何发起一个HTTP请求和如何建立一个Socket连接区别不大,只不过outputStream. write写的二进制字节数据格式要符合HTTP协议。浏览器在建立Socket连接之前,必须根据地址栏里输入的URL的域名DNS解析出IP地址,再根据这个IP地址和默认80端口与远程服务器建立Socket连接,然后浏览器根据这个URL组装成一个get类型的HTTP请求头,通过outputStream.write发送到目标服务器,服务器等待inputStream.read返回数据,最后断开这个连接。
当然,不同浏览器在如何使用这个已经建立好的连接,以及根据什么规则来管理连接,有各种不同的实现方法。一句话,发起一个HTTP请求的过程就是建立一个Socket通信的过程。
既然发起一个HTTP连接本质上就是建立一个Socket连接,那么我们完全可以模拟浏览器来发起HTTP请求,这很好实现,也有很多方法实现,如HttpClient就是一个开源的通过程序实现的处理HTTP请求的工具包。当然如果你对HTTP协议的数据结构非常熟悉,你完全可以自己再实现另外一个HttpClient,甚至可以自己写个简单的浏览器。
下面是一个基本的HttpClient的调用示例:
HttpClient httpClient = createHttpClient(); PostMethod postMethod; String domainName = Switcher.domain; postMethod = new PostMethod(domainName); postMethod.addRequestHeader("Content-Type", "application/x-www-form- urlencoded; charset=GBK"); for (FilterData filterData : filterDatas) { postMethod.addParameter("ip", filterData.ip); postMethod.addParameter("count", String.valueOf(filterData.count)); } try { httpClient.executeMethod(postMethod); postMethod.getResponseBodyAsString(); } catch (Exception e) { logger.error(e); }
处理Java中使用非常普遍的HttpClient还有很多类似的工具,如Linux中的curl命令,通过curl + URL就可以简单地发起一个HTTP请求,非常方便。
例如,curl "http://item.taobao.com/item.htm?id=1264" 可以返回这个页面的HTML数据,如图1-2所示。
图1-2 HTTP请求返回的HTML数据
也可以查看这次访问的HTTP协议头的信息,加上-I选项,如图1-3所示。
图1-3 HTTP协议头的信息
还可以在访问这个URL时增加HTTP头,通过-HI选项实现,如图1-4所示。
图1-4 访问URL时增加HTTP头
因为缺少Cookie信息,所以上面的访问返回302状态码,必须增加Cookie才能正确访问该链接,如下所示:
[junshan@v101055.sqa.cm4 admin]$ curl -I "http://switch.taobao.com:9999/ repository.htm" -H "Cookie:cna=sd0/BjeZulwCAfIdAHkzZZqC; _t_track=121.0.29. 242.1320938379988839;" HTTP/1.1200 OK Date: Sat, 25 Feb 2012 08:41:20 GMT Server: Apache Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT Vary: Accept-Encoding Content-Type: text/html;charset=GBK