最近打算写一些前端知识的总结以及个人的见解,现在是第一篇,先写一下关于HTTP相关的东西。
之前写过一篇文章是关于curl命令与HTTP请求,里面也提到一些关于HTTP的东西,这篇文章会再补充一下。
HTTP是什么
HTTP即超文本传输协议(Hyper Text Transfer Protocol),是一个简单的请求-响应协议,用于传输数据。
HTTP诞生之初主要是应用于WEB端内容获取,随着互联网的发展,更多的内容开始被展示(更多的图片文件),排版变得更精美(更多的CSS),更复杂的交互也被引入(更多的JS)。用户打开一个网站首页所加载的数据总量和请求的个数也在不断增加。所以HTTP也是在不断进化中。
一个完整的HTTP请求体可以参阅之前的文章 《curl命令与HTTP请求》。
HTTP常见的请求方法、状态消息以及头(headers)
请求方法
GET 方法
GET 是最常用的 HTTP 请求方法,会显示请求指定的资源,并返回响应主体,一般对它的期望是安全且幂等的(指对同一个 URL 的多个请求应该返回同样的结果)。
所谓安全是指该操作用于获取信息而非修改信息。换句话说,GET 请求一般不应产生副作用。就是说,它仅仅是获取资源信息,就像数据库查询一样,不会修改和增加数据,不会影响资源的状态。
POST 方法
POST 方法用于向指定资源提交数据,请求服务器进行处理(例如提交表单或者上传文件),数据被包含在请求本文中。
POST 请求可能会创建新的资源或修改现有资源,或二者皆有。每次提交,表单的数据被浏览器用编码到HTTP请求的body里。
浏览器发出的POST请求的body的主要格式
- application/x-www-form-urlencoded 用来传输简单的数据,如 "key1=value1&key2=value2" 这样的格式。
- multipart/form-data 主要用来传输文件内容。
- application/json 告诉服务端消息主体是序列化后的 JSON 字符串。
- text/plain 纯文本格式
下图是关于GET和POST的区别
HEAD 方法
与 GET 方法一样,都是向服务器发出指定资源的请求,只不过服务器将不传回资源的本文部分,只返回头部消息。
它的好处在于,使用这个方法可以在不必传输全部内容的情况下,就可以获取其中“关于该资源的信息”(元信息或称元数据),对资源的首部进行检查,比如:
- 如果 GET /users 返回用户列表,
- 那么 HEAD /users 将发出相同的请求,但不会返回用户列表。
HEAD 方法的使用场景
- 在不获取资源的情况下,了解资源的一些信息,比如资源类型;
- 通过查看响应中的状态码,可以确定资源是否存在;
- 通过查看首部,测试资源是否被修改。
PUT 方法
PUT 方法用于将数据发送到服务器来创建/更新资源。
PUT 与 POST 方法的区别在于,PUT 方法是幂等的:调用一次与连续调用多次是等价的(即没有副作用),而连续调用多次 POST 方法可能会有副作用,比如将一个订单重复提交多次。
DELETE 方法
DELETE 方法就是请求服务器删除指定 URL 所对应的资源。但是,客户端无法保证删除操作一定会被执行,因为 HTTP 规范允许服务器在不通知客户端的情况下撤销请求。
OPTIONS 方法
OPTIONS 方法用于获取目的资源所支持的通信选项。
客户端可以对特定的 URL 使用 OPTIONS 方法,也可以对整站(通过将 URL 设置为“*”)使用该方法。
若请求成功,则它会在 HTTP 头中包含一个名为 “Allow” 的头,值是所支持的方法,如 “GET, POST”。
使用示例
可以使用 OPTIONS 方法对服务器发起请求,以检测服务器支持哪些 HTTP 方法,响应报文包含一个 Allow 首部字段,该字段的值表明了服务器支持的所有 HTTP 方法:
HTTP/1.1 200 OK
Allow: OPTIONS, GET, HEAD, POST
Cache-Control: max-age=604800
Date: Thu, 13 Oct 2016 11:45:00 GMT
Expires: Thu, 20 Oct 2016 11:45:00 GMT
Server: EOS (lax004/2813)
x-ec-custom-error: 1
Content-Length: 0
个人见解
其实无论什么请求方法,请求的数据都可以选择放在URL或者body中。不存在GET请求的数据只能在放在URL,POST的请求只能放在body的说法。只是当GET请求时,数据放在body会被忽略或者警告。而当POST请求时,数据也可以放在URL上,此时后端获取数据的方法应该使用getQueryString的方法,但是这样就违背了POST请求的初衷,所以使用POST请求的时候,还是尽量将数据放在body上。
常见的状态消息(状态码)
2xx:成功
200 OK - 请求成功
3xx:重定向
302 Found - 所请求的页面已经临时转移至新的url。
304 Not Modified - 未按预期修改文档。客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓存的文档还可以继续使用。
4xx:客户端错误
400 Bad Request - 错误请求,客户端请求有语法错误,不能被服务器所理解。
401 Unauthorized - 未授权,客户端的请求需要身份验证,服务器验证未通过。
403 Forbidden - 对被请求页面的访问被禁止
404 Not Found - 服务器无法找到被请求的页面
405 Method Not Allowed - 请求中指定的方法不被允许
5xx:服务器错误
500 Internal Server Error - 请求未完成,服务器遇到不可预知的情况
501 Not Implemented - 请求未完成,服务器不支持所请求的功能
502 Bad Gateway - 请求未完成,服务器从上游服务器收到一个无效的响应
503 Service Unavailable - 请求未完成,服务器临时过载或宕机
504 Gateway Timeout - 网关超时
常见的 HEADERS
请求头 Request Header
字段名 | 说明 |
---|---|
Accept | 用户代理可处理的媒体类型,表示客户端希望接收的数据类型 |
Accept-Charset | 优先的字符集 |
Accept-Encoding | 优先的内容编码 |
Host | 指定资源所在服务器 |
Referer | 告诉服务器该网页是从哪个页面链接过来 |
If-Match | 比较实体标记(ETag) |
If-Modified-Since | 比较资源的更新时间 |
If-None-Match | 比较实体标记(与If-Match相反) |
响应头 Response Header
字段名 | 说明 |
---|---|
ETag | 资源的匹配信息 |
Location | 令客户端重定向至指定URI |
Server | 包含有关原始服务器用来处理请求的软件的信息 |
Last-Modified | 资源修改的日期及时间 |
Access-Control-Allow-Methods | 明确客户端所要访问的资源允许使用的方法或方法列表 |
除此之外,也有一些通用头可用于请求或响应
字段名 | 说明 |
---|---|
Content-Type | 实体头部用于指示资源的 MIME 类型(media type)。 |
Content-Encoding | 实体主体适用的编码方式 |
Content-Length | 实体主体的大小(字节) |
更多 HTTP Header 信息可参考 MDN HTTP 文档
浏览器缓存机制介绍
总的来说,可以分为三种验证机制来实现缓存:
- 设置资源有效时间
- 比较资源的最新修改时间
- 比较资源的唯一标识(ETag,类似版本号,当资源发生改变的时候标识会随之改变)
设置资源有效时间
当客户端第一次请求完成的时候,服务端会在响应头加上 Cache-Control 或 Expires 字段,用来表示该资源的有效时间。
当浏览器第二次发送请求时,会先根据该字段进行验证,如在有效时间内,则直接使用资源副本。
注意:Expires 是 HTTP 1.0 的字段,而 Cache-Control 是 HTTP 1.1 的字段,当 Expires 与 Cache-Control 同时存在时,Cache-Control 的优先级要高于 Expires。所以可以忽略上面提到的 Expires。因为 Cache-Control 相对于 Expires 更加具体,细致。参见 Cache-Control文档
比较资源的最新修改时间
该方法主要是利用 Last-Modified 和 If-Modified-Since 配合完成:
当客户端第一次请求完成的时候,服务端会在响应头加上 Last-Modified 字段,用来表示该资源的最新修改时间。
当浏览器第二次发送请求时,会在请求头的 If-Modified-Since 字段加上上次请求返回的 Last-Modified 时间。HTTP 服务器收到该时间后,会对该资源的修改时间进行对比,如最新修改时间一致,则证明该资源无更新,然后响应 304 告诉客户端可直接使用浏览器资源副本。若最新修改时间不一致,服务器则响应 200,并向客户端发送新的资源。
比较资源的唯一标识
此方法与比较资源的最新修改时间类似,主要是利用 If-None-Match 和 ETag 配合完成:
当客户端第一次请求完成的时候,服务端会在响应头加上 Etag 字段,用来表示该资源的唯一标识。
当浏览器第二次发送请求时,会在请求头的 If-None-Match 字段加上上次请求返回的 ETag 标识。HTTP 服务器收到该标识后,会对该资源的标识进行对比,如一致,则证明该资源无更新,然后响应 304 告诉客户端可直接使用浏览器资源副本。若不一致,服务器则响应 200,并向客户端发送新的资源。
下面用一张流程图来完整说明当浏览器发起 HTTP 请求时缓存机制的过程:
Etag相对于Last-Modified的优势:
- Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间;
- 如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存;
- 有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形。
Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,所以能够更加准确的控制缓存。
最后,虽然说浏览器缓存对用户体验有极大的好处,但是作为开发者,我们在开发的时候则需要禁止这「讨厌」浏览器缓存,方法是打开浏览器的开发者工具,在 Network 中有个 Disable cache ,钩上就可以了,钩上后浏览器会忽略掉文档过期验证和服务器再验证的过程,直接向服务器请求最新的资源。