HTTP 学习*
基本概念*
URI*
统一资源标识符,包括定位符 URL 和名称 URN。
请求和响应报文*
请求报文*
请求行、请求头、空行分割的消息主体。

响应报文*
状态行、响应头、空行分割的消息主体。

HTTP 方法*
请求报文的第一行为请求行,包含了方法字段。
GET*
获取资源。
HEAD*
获取报文首部,和 GET 类似,但不报文实体主体部分。
用于确认 URL 的有效性以及资源更新的日期时间等。
POST*
传输实体主体。
PUT*
自身不带验证机制,任何人都可以上传文件,存在安全性问题。
PATCH*
对资源进行部分修改。
DELETE*
删除文件,同样不带验证机制。
OPTIONS*
查询支持的方法
CONNECT*
要求与代理服务器通信时建立隧道。
使用 SSL 和 TLS 协议把通信内容加密后传输。
TRACE*
追踪路径,服务器将通信路径返回给客户端。
HTTP 状态码*
服务器返回的响应报文第一行为状态行,包含了状态码以及原因短语,用来告知客户端请求的结果。
具体见 HTTP 状态码
HTTP 首部*
有 4 种类型的首部字段:通用首部字段、请求首部字段、响应首部字段和实体首部字段。
以下列出,供查阅。
通用首部字段*
| 首部字段名 | 说明 |
|---|---|
| Cache-Control | 控制缓存的行为 |
| Connection | 控制不再转发给代理的首部字段、管理持久连接 |
| Date | 创建报文的日期时间 |
| Pragma | 报文指令 |
| Trailer | 报文末端的首部一览 |
| Transfer-Encoding | 指定报文主体的传输编码方式 |
| Upgrade | 升级为其他协议 |
| Via | 代理服务器的相关信息 |
| Warning | 错误通知 |
请求首部字段*
| 首部字段名 | 说明 |
|---|---|
| Accept | 用户代理可处理的媒体类型 |
| Accept-Charset | 优先的字符集 |
| Accept-Encoding | 优先的内容编码 |
| Accept-Language | 优先的语言(自然语言) |
| Authorization | Web 认证信息 |
| Expect | 期待服务器的特定行为 |
| From | 用户的电子邮箱地址 |
| Host | 请求资源所在服务器 |
| If-Match | 比较实体标记(ETag) |
| If-Modified-Since | 比较资源的更新时间 |
| If-None-Match | 比较实体标记(与 If-Match 相反) |
| If-Range | 资源未更新时发送实体 Byte 的范围请求 |
| If-Unmodified-Since | 比较资源的更新时间(与 If-Modified-Since 相反) |
| Max-Forwards | 最大传输逐跳数 |
| Proxy-Authorization | 代理服务器要求客户端的认证信息 |
| Range | 实体的字节范围请求 |
| Referer | 对请求中 URI 的原始获取方 |
| TE | 传输编码的优先级 |
| User-Agent | HTTP 客户端程序的信息 |
响应首部字段*
| 首部字段名 | 说明 |
|---|---|
| Accept-Ranges | 是否接受字节范围请求 |
| Age | 推算资源创建经过时间 |
| ETag | 资源的匹配信息 |
| Location | 令客户端重定向至指定 URI |
| Proxy-Authenticate | 代理服务器对客户端的认证信息 |
| Retry-After | 对再次发起请求的时机要求 |
| Server | HTTP 服务器的安装信息 |
| Vary | 代理服务器缓存的管理信息 |
| WWW-Authenticate | 服务器对客户端的认证信息 |
实体首部字段*
| 首部字段名 | 说明 |
|---|---|
| Allow | 资源可支持的 HTTP 方法 |
| Content-Encoding | 实体主体适用的编码方式 |
| Content-Language | 实体主体的自然语言 |
| Content-Length | 实体主体的大小 |
| Content-Location | 替代对应资源的 URI |
| Content-MD5 | 实体主体的报文摘要 |
| Content-Range | 实体主体的位置范围 |
| Content-Type | 实体主体的媒体类型 |
| Expires | 实体主体过期的日期时间 |
| Last-Modified | 资源的最后修改日期时间 |
具体应用*
连接管理*
1. 短连接与长连接*
长连接只需要建立一次 TCP 连接就能进行多次 HTTP 通信。
- HTTP/1.1 开始默认为长连接,要断开时由客户端或服务端提出断开,使用
Connection:close; - 之前默认为短连接,使用
Connection:Keep-Alive开启长连接。
2. 流水线*
默认情况下,HTTP 请求是按序发出的,下一个请求只有在当前请求收到响应之后才会被发出。长连接中使用流水线,不需要等待响应返回,以减少延迟。
Cookie*
HTTP/1.1 引入 Cookie 保存状态信息。
Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器之后向同一服务器再次发起请求时被携带上,用于告知服务器两个请求是否来自同一浏览器。
1. 用途*
- 会话状态管理
- 个性化设置
- 浏览器行为跟踪
2. 创建过程*
服务器发送的响应报文包括 Set-Cookie 首部字段,客户端得到响应报文后把 Cookie 内容保存到浏览器中。
客户端之后对同一个服务器发送请求时,会从浏览器取出 Cookie 信息并通过 Cookie 请求首部字段发送给浏览器。
3. 分类*
- 会话期 Cookie:浏览器关闭后自动删除。
- 持久性 Cookie:指定过期时间或有效期。
4. 作用域*
Domain 标识指定了哪些主机可以接收 Cookie。如果不指定,默认为当前文档的主机(不包括子域名)。如果指定了 Domain,一般包括子域名。
Path 标识制定了主机下的哪些路径可以接收 Cookie(该 URL 路径必须存在于请求 URL 中),子路径也会被匹配。
5. JavaScript*
浏览器通过 document.cookie 属性可创建新的 Cookie,也可通过该属性访问非 HttpOnly 标识的 Cookie。
6. HttpOnly*
标记为 HttpOnly 的 Cookie 不能被 js 调用。一定程度可避免 XSS。
7. Secure*
标记为 Secure 的 Cookie 只能通过 HTTPS 请求发送给客户端。
8. Session*
除了将用户信息通过 Cookie 存储在用户浏览器中,也可以利用 Session 存储在服务器端,更安全。
使用 Session 维护用户登录状态的过程如下:
- 用户登录,提交包含用户名和密码的表单,放入 HTTP 请求报文中;
- 服务器验证该用户名和密码,如果正确则把用户信息存储到 Redis 中,它在 Redis 中的 Key 成为 Session ID;
- 服务器返回的响应报文的 Set-Cookie 首部字段包含了这个 Session ID,客户端收到响应报文之后将该 Cookie 值存入浏览器;
- 客户端之后对同一个服务器进行请求时会包含该 Cookie 值,服务器收到之后提取出 Session ID,从 Redis 中取出用户信息,继续业务操作。
Session ID 的安全性。
9. 浏览器禁用 Cookie*
此时无法使用 Cookie 来保存用户信息,只能使用 Session。Session ID 作为 URL 的参数进行传递。
10. Cookie 与 Session 选择*
- Cookie 只能存储 ASCII 字符串,而 Session 则可以存储任何类型的数据,因此在考虑数据复杂性时首选 Session;
- Cookie 存储在浏览器中,容易恶意查看。可以将 Cookie 加密,在服务器解密。
- 对于大型网站,如果用户所有的信息都存储在 Session 中,开销大。
缓存*
1. 优点*
- 缓解服务器压力;
- 降低客户端获取资源的延迟:缓存通常位于内存中,读取速度快。
2. 实现方法*
- 代理服务器缓存;
- 客户端浏览器进行缓存。
3. Cache-Control*
HTTP/1.1 通过 Cache-Control 首部字段来控制缓存。
- 禁用缓存:no-store
- 强制确认缓存:no-cache
- 私有缓存和公有缓存:private,只能被单独用户使用,一般存储在用户浏览器;public,公共缓存,可被多个用户使用,一般存储在代理服务器;
- 缓存过期机制:max-age 出现在请求报文,且缓存资源的缓存时间小于指定的时间,则接收缓存,出现在响应报文,表示缓存资源在缓存服务器中保存的时间;expires 字段也可用于告知缓存服务器该资源什么时候过期。HTTP/1.1 中优先处理 max-age,而 1.0 忽略。
4. 缓存验证*
ETag 首部字段是资源的唯一标识,将缓存资源的 ETag 值放入 If-None-Match 首部,服务器收到请求后,判断该 ETag 与最新 ETag 值是否一致,一致则表示缓存有效,返回 304 Not Modified。
Last-Modified 首部字段也可以用于缓存验证,包含在源服务器的响应报文中,指示服务器对资源的最后修改时间。客户端收到后可以在后续请求中带上 If-Modified-Since 验证缓存,服务器只在所请求的资源在给定时间之后修改时才返回资源,否则返回 304。
内容协商*
通过内容协商返回最合适的内容。
1. 类型*
- 服务端驱动型,客户端设置特定的 HTTP 首部字段,例如 Accept、Accept-Charset、Accept-Encoding、Accept-Language,服务器根据这些字段返回特定资源。
- 服务器很难知道客户端浏览器的全部信息;
- 客户端提供的信息冗长;
- 给定的资源需要返回不同的展现形式,共享缓存的效率降低。
- 代理驱动型,服务器返回 300 Multiple Choices 或者 406 Not Acceptable,客户端从中选择最合适的那个资源。
2. Vary*
使用内容协商的情况下,只有当缓存服务器中的缓存满足内容协商条件时,才能使用该缓存,否则应该向源服务器请求该资源。
例如,一个客户端发送了一个包含 Accept-Language 首部字段的请求之后,源服务器返回的响应包含 Vary: Accept-Language 内容,缓存服务器对这个响应进行缓存之后,在客户端下一次访问同一个 URL 资源,并且 Accept-Language 与缓存中的对应的值相同时才会返回该缓存。
内容编码*
内容编码将实体主体进行压缩,从而减少传输的数据流。
常用的内容编码有:gzip、compress、deflate、identity。
浏览器发送 Accept-Encoding 首部,包含它支持的压缩算法,以及各自的优先级。浏览器选择一种,发送 Content-Encoding 首部告知浏览器选择的算法。同时 Vary 字段也要包含 Content-Encoding。
范围请求*
如果网络出现中断,服务器只发送了一部分数据,范围请求可以使客户端只请求服务器未发送的那部分数据,从而避免服务器重新发送所有数据。
1. Range*
在请求报文中添加 Range 首部字段指定请求的范围,Range: bytes=0-1023。
请求成功则服务器返回的响应包含 206 Partial Content 状态码,同时 Content-Range: bytes 0-1023。
2. Accept-Ranges*
响应首部字段 Accept-Ranges 用于告知客户端是否能处理范围请求,可以处理用 bytes,否则用 none。
3. 响应状态码*
- 请求成功,返回 206 Partial Content;
- 请求范围越界,返回 416 Requested Range Not Satisfiable;
- 不支持范围请求,返回 200。
分块传输编码*
Chunked Transfer Encoding,可以把数据分割成多块,让浏览器逐步显示页面。
多部份对象集合*
一份报文主体内可含有多种类型的实体同时发送,每个部分之间用 boundary字段定义的分隔符进行分隔,每个部分都可以有首部字段。
虚拟主机*
HTTP/1.1 使用虚拟主机技术,使得一台服务器拥有多个域名,并且逻辑上可以看成多个服务器。
通信数据转发*
1. 代理*
代理服务器接收客户端的请求,并且转发给其他服务器。
使用代理的目的主要是:
- 缓存
- 负载均衡
- 网络访问控制
- 访问日志记录
代理服务器分为正向代理和反向代理两种,用户可以察觉正向代理的存在,而反向代理一般位于内部网络。
2. 网关*
网关服务器会将 HTTP 转换为其他协议进行通信,从而请求其他非 HTTP 服务器的服务。
3. 隧道*
使用 SSL 等加密手段,在客户端和服务器之间建立一条安全的通信线路。
HTTPS*
HTTP 有以下的安全问题:
- 明文通信,会被窃听;
- 不验证通信方的身份,通信方的身份有可能遭遇伪装;
- 无法证明报文的完整性,报文有可能遭篡改。
HTTPS 是让 HTTP 先和 SSL 通信,再由 SSL 和 TCP 通信,使用了隧道通信。
通过使用 SSL,HTTPS 具有了加密防窃听、认证防伪装和完整性保护防篡改。
加密*
1. 对称密钥加密*
加解密使用同一密钥,运算快,传输过程不安全。
2. 非对称密钥加密*
密钥分为公钥私钥,公钥可以公开,私钥无法被其他人获取,运算慢。
3. HTTPS 采用的加密方式*
混合加密,使用非对称加密加密对称加密的密钥。
认证*
通过使用证书对通信方进行认证。
数字证书认证机构 Certificate Authority 是客户端与服务端双方都可信赖的第三方机构。
服务器向 CA 提出公开密钥申请,CA 在判明申请者身份之后,会对已申请的公开密钥做数字签名。并分配这个已签名的公开密钥,并将该公开密钥放入公开密钥证书后绑定。
进行 HTTPS 通信时,服务器会把证书发送给客户端。客户端取得公钥之后,先使用数据签名验证,通过后可开始通信。

完整性保护*
SSL 提供报文摘要进行完整性保护。
HTTP 也提供了 MD5 报文摘要,但是不安全,也可被篡改。
HTTPS 的缺点*
- 需要进行加密解密,速度会慢;
- 证书付费。
HTTP/2.0*
HTTP/1.x 缺陷*
HTTP/1.x 的简单是以牺牲性能为代价的:
- 客户端需要使用多个连接才能实现并发和缩短延迟;
- 不会压缩请求和响应首部,导致不必要的网络流量;
- 不支持有效的资源优先级,底层 TCP 连接利用率低下。
二进制分帧层*
HTTP/2.0 将报文分为 HEADERS 帧和 DATA 帧,都是二进制格式的。

通信过程中,只会有一个 TCP 连接存在,承载了任意数量的双向数据流。
- 一个数据流都有一个唯一标识符和可选的优先级i西南西,用于承载双向信息。
- 消息是与逻辑请求或响应对于的完整的一系列帧。
- 帧是最小的通信单位,来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装。
服务端推送*
HTTP/2.0 在客户端请求一个资源时,会把相关的资源一起发送给客户端。
首部压缩*
HTTP/1.1 的首部带有大量信息,且每次都要重复发送。
HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见过的首部字段表,从而避免重复传输。同时使用 Huffman 编码对首部字段进行压缩。

HTTP/1.1 新特性*
- 默认长连接
- 支持流水线
- 支持同时打开多个 TCP 连接
- 支持虚拟主机
- 新增状态码 100 Continue
- 支持分块传输编码
- 新增缓存处理执行 max-age
GET 和 POST 比较*
作用*
GET 用于获取资源,POST 用于传输实体主体。
参数*
GET 和 POST 请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体主体中。
URL 只支持 ASCII 码,因此 GET 参数会先编码。POST 支持标准字符集。
安全*
安全的 HTTP 方法不会改变服务器状态,即只读。
GET 安全,而 POST 传送实体内容,会改变服务器状态。
安全的还有 HEAD、OPTIONS;不安全的像 PUT、DELETE。
幂等性*
幂等性的方法即同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的。即不具有副作用。
安全的方法是幂等的,PUT 和 DELETE 是幂等的。而 POST 表示。
可缓存*
如果要对响应进行缓存,要满足以下条件:
- 请求报文的 HTTP 方法本身是可缓存的,包括 GET 和 HEAD,PUT 和 DELETE 不可缓存,POST 多数情况下不可缓存。
- 响应报文的状态码是可缓存的,包括:200、203、204、206、300、301、404、405、410、414 和 501 等。
- 响应报文的 Cache-Control 首部字段未禁用缓存。
XMLHttpRequest*
XMLHttpRequest 是一个 API,它为客户端提供了在客户端和服务器之间传输数据的功能。它提供了一个通过 URL 来获取数据的简单方式,并且不会使整个页面刷新。这使得网页只更新一部分页面而不会打扰到用户。在 AJAX 中大量使用。
- 使用 XMLHttpRequest 的 POST 方法时,浏览器会先发送 Header 再发送 Data。
- 而 GET 方法会一起发送。