## 十八、HTTP 和表单
> 通信在实质上必须是无状态的,从客户端到服务器的每个请求都必须包含理解请求所需的所有信息,并且不能利用服务器上存储的任何上下文。
>
> Roy Fielding,《Architectural Styles and the Design of Network-based Software Architectures》
我们曾在第 13 章中提到过超文本传输协议(HTTP),万维网中通过该协议进行数据请求和传输。在本章中会对该协议进行详细介绍,并解释浏览器中JavaScript访问HTTP的方式。
### 协议
当你在浏览器地址栏中输入`eloquentjavascript.net/18_http.html`时,浏览器会首先找到和`eloquentjavascript.net`相关的服务器的地址,然后尝试通过 80 端口建立 TCP 连接,其中 80 端口是 HTTP 的默认通信端口。如果该服务器存在并且接受了该连接,浏览器可能发送如下内容。
```http
GET /18_http.html HTTP/1.1
Host: eloquentjavascript.net
User-Agent: Your browser's name
```
然后服务器会通过同一个链接返回如下内容。
```http
HTTP/1.1 200 OK
Content-Length: 65585
Content-Type: text/html
Last-Modified: Mon, 08 Jan 2018 10:29:45 GMT
... the rest of the document
```
浏览器会选取空行之后的响应部分,也就是正文(不要与 HTML `
`标签混淆),并将其显示为 HTML 文档。
由客户端发出的信息叫作请求。请求的第一行如下。
```http
GET /17_http.html HTTP/1.1
```
请求中的第一个单词是请求方法。GET表示我们希望得到一个我们指定的资源。其他常用方式还有DELETE,用于删除一个资源;PUT用于替换资源;POST用于发送消息。需要注意的是服务器并不需要处理所有收到的请求。如果你随机访问一个网站并请求删除主页,服务器很有可能会拒绝你的请求。
方法名后的请求部分是所请求的资源的路径。在最简单的情况下,一个资源只是服务器中的一个文件。不过,协议并没有要求资源一定是实际文件。一个资源可以是任何可以像文件一样传输的东西。很多服务器会实时地生成这些资源。例如,如果你打开`github.com/marijnh`,服务器会在数据库中寻找名为`marijnjh`的用户,如果找到了则会为该用户的生成介绍页面。
请求的第一行中位于资源路径后面的HTTP/1.1用来表明所使用的HTTP协议的版本。
在实践中,许多网站使用 HTTP v2,它支持与版本 1.1 相同的概念,但是要复杂得多,因此速度更快。 浏览器在与给定服务器通信时,会自动切换到适当的协议版本,并且无论使用哪个版本,请求的结果都是相同的。 由于 1.1 版更直接,更易于使用,因此我们将专注于此。
服务器的响应也是以版本号开始的。版本号后面是应答状态,首先是一个三位的状态码,然后是一个可读的字符串。
```http
HTTP/1.1 200 OK
```
以2开头的状态码表示请求成功。以4开头的状态码表示请求中有错误。404是最著名的HTTP状态码了,表示找不到资源。以5开头的状态码表示服务器端出现了问题,而请求没有问题。
请求或响应的第一行后可能会有任意个协议头,多个形如“name:value”的行表明了和请求或响应相关的更多信息。这些是示例响应中的头信息。
```http
Content-Length: 65585
Content-Type: text/html
Last-Modified: Thu, 04 Jan 2018 14:05:30 GMT
```
这些信息说明了响应文档的大小和类型。在这个例子中,响应是一个65585字节的HTML文档,同时也说明了该文档最后的更改时间。
多数大多数协议头,客户端或服务器可以自由决定需要在请求或响应中包含的协议头,不过也有一些协议头是必需的。例如,指明主机名的Host头在请求中是必须的,因为一个服务器可能在一个IP地址下有多个主机名服务,如果没有Host头,服务器则无法判断客户端尝试请求哪个主机。
请求和应答可能都会在协议头后包含一个空行,后面则是消息体,包含所发送的数据。GET和DELETE请求不单独发送任何数据,但PUT和POST请求则会。同样地,一些响应类型(如错误应答)不需要有消息体。
### 浏览器和 HTTP
正如上例所示,当我们在浏览器地址栏输入一个URL后浏览器会发送一个请求。当HTML页面中包含有其他的文件,例如图片和JavaScript文件时,浏览器也会一并获取这些资源。
一个较为复杂的网站通常都会有10到200个不等的资源。为了可以很快地取得这些资源,浏览器会同时发送多个`GET`请求,而不是一次等待一个请求。此类文档都是通过GET方法来获取的。
HTML页面可能包含表单,用户可以在表单中填入一些信息然后由浏览器将其发送到服务器。如下是一个表单的例子。
```html
```
这段代码描述了一个有两个输入域的表单:较小的输入域要求用户输入姓名,较大的要求用户输入一条消息。当点击发送按钮时,表单就提交了,这意味着其字段的内容被打包到 HTTP 请求中,并且浏览器跳转到该请求的结果。
当`