
5.1 HTTP简介
当用户打开浏览器,输入一个URL地址,就能接收到远程HTTP服务器发送过来的网页。浏览器就是最常见的HTTP客户程序。如图5-1所示,HTTP客户程序必须先发出一个HTTP请求,然后才能接收到来自HTTP服务器的响应。

图5-1 HTTP客户程序与HTTP服务器的通信过程
HTTP客户程序和HTTP服务器分别由不同的软件开发商提供,它们都可以用任意的编程语言编写。用VC编写的HTTP客户程序能否与用Java编写的HTTP服务器顺利通信呢?答案是肯定的。HTTP严格规定了HTTP请求和HTTP响应的数据格式,只要HTTP服务器与客户程序都遵守HTTP,就能彼此看得懂对方发送的消息。
5.1.1 HTTP请求格式
HTTP规定,HTTP请求由3部分构成,分别是:。
·请求方法、URI、HTTP的版本
·请求头(Request Header)
·请求正文(Request Content)
下面是一个HTTP请求的例子。

1.请求方式、URI、HTTP的版本
HTTP请求的第1行包括请求方式、URI和协议版本这3项内容,以空格分开。

在以上代码中,“POST” 表示请求方式,“/hello.jsp”表示URI,“HTTP/1.1”表示HTTP的版本。
根据HTTP,HTTP请求可以使用多种请求方式,主要包括以下几种。
·GET:这种请求方式最为常见,客户程序通过这种请求方式访问服务器上的一个文档,服务器把文档发送给客户程序。
·POST:客户程序可通过这种方式发送大量信息给服务器。在HTTP请求中除了包含要访问的文档的URI,还包括大量的请求正文,这些请求正文中通常会包含大量HTML表单数据。
·HEAD:客户程序和服务器之间交流一些内部数据,服务器不会返回具体的文档。当使用GET和POST方法时,服务器最后都将特定的文档返回给客户程序。而HEAD请求方式则不同,它仅仅交流一些内部数据,这些数据不会影响用户浏览网页的过程,可以说对用户是透明的。HEAD请求方式通常不单独使用,而是为其他请求方式起辅助作用。一些搜索引擎使用HEAD请求方式来获得网页的标志信息,还有一些HTTP服务器在进行安全认证时,用这个方式来传递认证信息。
·PUT:客户程序通过这种方式把文档上传给服务器。
·DELETE:客户程序通过这种方式来删除远程服务器上的某个文档。客户程序可以利用PUT和DELETE请求方式来管理远程服务器上的文档。
GET和POST请求方式最常用,而PUT和DELETE请求方式并不常用,因而不少HTTP服务器并不支持PUT和DELETE请求方式。
统一资源定位符(Universal Resource Identifier,URI)用于标识要访问的网络资源。在HTTP请求中,通常只要给出相对于服务器的根目录的相对目录即可,因此以“/”开头。
HTTP请求的第1行的最后一部分内容为客户程序使用的HTTP的版本。
2.请求头(Request Header)
请求头包含许多有关客户端环境和请求正文的有用信息。例如,请求头可以声明浏览器的类型、所用的语言、请求正文的类型,以及请求正文的长度等。

3.请求正文(Request Content)
HTTP规定,请求头和请求正文之间必须以空行分割(即只有CRLF符号的行),这个空行非常重要,它表示请求头已经结束,接下来是请求正文。请求正文中可以包含客户以POST方式提交的表单数据。

在以上HTTP请求例子中,请求正文只有一行内容。在实际应用中,HTTP请求的正文可以包含更多的内容。
提示
CRLF(Carriage Return Linefeed)指回车符和行结束符“\r\n”。
本书2.2节的例程2-6(HTTPClient.java)是一个简单的HTTP客户程序,它发送的HTTP请求信息就严格遵守上述规范。


5.1.2 HTTP响应格式
和HTTP请求相似,HTTP响应也由3部分构成,分别是:
·HTTP的版本、状态代码、描述
·响应头(Response Header)
·响应正文(Response Content)
下面是一个HTTP响应的例子。

1.HTTP的版本、状态代码、描述
HTTP响应的第1行包括服务器使用的HTTP的版本、状态代码,以及对状态代码的描述,这3项内容之间以空格分割。在本例中,使用HTTP1.1,状态代码为200,该状态代码表示服务器已经成功地处理了客户端发出的请求。

状态代码是一个3位整数,以1、2、3、4或5开头。
·1xx:信息提示,表示临时的响应。
·2xx:响应成功,表明服务器成功的接收了客户端请求。
·3xx:重定向。
·4xx:客户端错误,表明客户端可能有问题。
·5xx:服务器错误,表明服务器由于遇到某种错误而不能响应客户请求。
以下是一些常见的状态代码。
·200:响应成功。
·400:错误的请求。客户发送的HTTP请求不正确。
·404:文件不存在。在服务器上没有客户要求访问的文档。
·405:服务器不支持客户的请求方式。
·500:服务器内部错误。
2.响应头(Response Header)
响应头也和请求头一样包含许多有用的信息,例如服务器类型、正文类型和正文长度等。

3.响应正文(Response Content)
响应正文就是服务器返回的具体的文档,最常见的是HTML网页。

HTTP请求头与请求正文之间必须用空行分割,同样,HTTP响应头与响应正文之间也必须用空行分隔。
5.1.3 测试HTTP请求
当用户在浏览器中输入一个URL后,浏览器就会生成一个HTTP请求,建立与远程HTTP服务器的连接,然后把HTTP请求发送给远程HTTP服务器,HTTP服务器再返回相应的网页,浏览器最后把这个网页显示出来。当浏览器与服务器之间的数据交换完毕,就会断开连接。如果用户希望访问新的网页,浏览器就必须再次建立与服务器的连接。
例程5-1(SimpleHttpServer)创建了一个非常简单的HTTP服务器,它接收客户程序的HTTP请求,把它打印到控制台。然后对HTTP请求做简单的解析,如果客户程序请求访问login.htm,就返回该网页,否则一律返回hello.htm网页。login.htm和hello.htm文件位于root目录下。
SimpleHttpServer监听80端口,按照阻塞模式工作,采用线程池来处理每个客户请求。
例程5-1 SimpleHttpServer.java(阻塞模式)



在chapter05根目录下运行“java SimpleHttpServer”命令,就启动了HTTP服务器,然后打开一个IE浏览器,按照如下步骤访问HTTP服务器。根据服务器端的控制台的打印结果,可以了解IE浏览器发送给服务器的HTTP请求信息。
(1)在IE浏览器中输入URL:http://localhost:80/login.htm,或者http://localhost/login.htm。在默认情况下,IE浏览器总是与远程HTTP服务器的80端口建立连接,因此在URL中可以不指定80端口。图5-2显示了IE浏览器接收到的网页,以及服务器接收到的HTTP请求。

图5-2 浏览器按照GET方式访问login.htm
从服务器端的打印结果可以看出,IE浏览器发送的HTTP请求采用GET方式,请求的URI为login.htm。服务器把login.htm文件发送给IE浏览器,IE浏览器将它呈现给用户。login.htm文件中的内容如下:

在login.htm文件中定义了一个HTML表单,它有两个输入框,分别用于输入用户名和口令。以上<form>元素的action属性指定当用户提交表单时所请求访问的网页,此处为hello.htm;method属性用于指定请求方式,此处为POST。
(2)在图5-2的网页中,输入用户名“weiqin”,口令“1234”,然后提交表单。图5-3显示了IE浏览器接收到的网页,以及服务器接收到的HTTP请求。

图5-3 浏览器按照POST方式访问hello.htm
从图5-3可以看出,当提交了表单后,浏览器将采用POST方式请求访问hello.htm。表单中输入的用户名和口令等数据位于HTTP请求的正文部分,正文与请求头之间以空行分割。请求头中的Content-Length项指定正文的长度,此处为43个字符。本例中的SimpleHttpServer并没有对请求正文做任何处理。在实际应用中,HTTP服务器应该具备解析请求正文,生成动态网页的能力。
(3)把login.htm文件中method属性的值改为“GET”。

再重复步骤(1)和(2),当再次提交表单时,浏览器将采用GET方式请求访问hello.htm。服务器端接收到的HTTP请求如下。

在GET方式下,表单中的数据将不再作为请求正文发送,而是直接放在HTTP请求的第1行的URI里面,文件名与表单数据之间以“?”分割。
在以上HTTP请求中,username和password也被称为请求参数,它们都有相应的参数值,比如username参数的值为weiqin,password参数的值为1234。服务器可以读取这些请求参数的值,然后作相应处理。在GET方式下,请求参数位于HTTP请求的第1行的URI中,而在POST方式下,请求参数位于HTTP请求的正文中。
提示
在实际运用中,直接在网络上输入原始的用户口令是很不安全的。通常需要对口令进行加密,然后发送加密后的口令。接收方接收到加密的口令后再对其进行解密。