## 十八、HTTP 和表单 > 原文:[HTTP and Forms](http://eloquentjavascript.net/18_http.html) > > 译者:[飞龙](https://github.com/wizardforcel) > > 协议:[CC BY-NC-SA 4.0](http://creativecommons.org/licenses/by-nc-sa/4.0/) > > 自豪地采用[谷歌翻译](https://translate.google.cn/) > > 部分参考了[《JavaScript 编程精解(第 2 版)》](https://book.douban.com/subject/26707144/) > 通信在实质上必须是无状态的,从客户端到服务器的每个请求都必须包含理解请求所需的所有信息,并且不能利用服务器上存储的任何上下文。 > > 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 请求中,并且浏览器跳转到该请求的结果。 当`