CS-Notes/notes/HTTP.md

949 lines
39 KiB
Java
Raw Normal View History

2019-04-25 18:24:51 +08:00
<!-- GFM-TOC -->
* [ 基础概念](#-基础概念)
* [请求和响应报文](#请求和响应报文)
2020-11-03 02:25:47 +08:00
* [URL](#url)
2019-04-25 18:24:51 +08:00
* [HTTP 方法](#二http-方法)
* [GET](#get)
* [HEAD](#head)
* [POST](#post)
* [PUT](#put)
* [PATCH](#patch)
* [DELETE](#delete)
* [OPTIONS](#options)
* [CONNECT](#connect)
* [TRACE](#trace)
* [HTTP 状态码](#三http-状态码)
* [1XX 信息](#1xx-信息)
* [2XX 成功](#2xx-成功)
* [3XX 重定向](#3xx-重定向)
* [4XX 客户端错误](#4xx-客户端错误)
* [5XX 服务器错误](#5xx-服务器错误)
* [HTTP 首部](#四http-首部)
* [通用首部字段](#通用首部字段)
* [请求首部字段](#请求首部字段)
* [响应首部字段](#响应首部字段)
* [实体首部字段](#实体首部字段)
* [具体应用](#五具体应用)
* [连接管理](#连接管理)
* [Cookie](#cookie)
* [缓存](#缓存)
* [内容协商](#内容协商)
* [内容编码](#内容编码)
* [范围请求](#范围请求)
* [分块传输编码](#分块传输编码)
* [多部分对象集合](#多部分对象集合)
* [虚拟主机](#虚拟主机)
* [通信数据转发](#通信数据转发)
* [HTTPS](#六https)
* [加密](#加密)
* [认证](#认证)
* [完整性保护](#完整性保护)
* [HTTPS 的缺点](#https-的缺点)
* [HTTP/2.0](#七http20)
* [HTTP/1.x 缺陷](#http1x-缺陷)
* [二进制分帧层](#二进制分帧层)
* [服务端推送](#服务端推送)
* [首部压缩](#首部压缩)
* [HTTP/1.1 新特性](#八http11-新特性)
* [GET POST 比较](#九get--post-比较)
* [作用](#作用)
* [参数](#参数)
* [安全](#安全)
* [幂等性](#幂等性)
* [可缓存](#可缓存)
* [XMLHttpRequest](#xmlhttprequest)
* [参考资料](#参考资料)
<!-- GFM-TOC -->
# 基础概念
2020-11-03 02:25:47 +08:00
## 请求和响应报文
2019-04-25 18:24:51 +08:00
2020-11-03 02:25:47 +08:00
客户端发送一个请求报文给服务器服务器根据请求报文中的信息进行处理并将处理结果放入响应报文中返回给客户端
2019-04-25 18:24:51 +08:00
2020-11-03 02:25:47 +08:00
请求报文结构
2019-04-25 18:24:51 +08:00
2020-11-03 02:25:47 +08:00
- 第一行是包含了请求方法URL协议版本
- 接下来的多行都是请求首部 Header每个首部都有一个首部名称以及对应的值
- 一个空行用来分隔首部和内容主体 Body
- 最后是请求的内容主体
```
GET http://www.example.com/ HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: max-age=0
Host: www.example.com
If-Modified-Since: Thu, 17 Oct 2019 07:18:26 GMT
If-None-Match: "3147526947+gzip"
Proxy-Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 xxx
param1=1&param2=2
```
2019-04-25 18:24:51 +08:00
2020-11-03 02:25:47 +08:00
响应报文结构
2019-04-25 18:24:51 +08:00
2020-11-03 02:25:47 +08:00
- 第一行包含协议版本状态码以及描述最常见的是 200 OK 表示请求成功了
- 接下来多行也是首部内容
- 一个空行分隔首部和内容主体
- 最后是响应的内容主体
2019-04-25 18:24:51 +08:00
2020-11-03 02:25:47 +08:00
```
HTTP/1.1 200 OK
Age: 529651
Cache-Control: max-age=604800
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 648
Content-Type: text/html; charset=UTF-8
Date: Mon, 02 Nov 2020 17:53:39 GMT
Etag: "3147526947+ident+gzip"
Expires: Mon, 09 Nov 2020 17:53:39 GMT
Keep-Alive: timeout=4
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Proxy-Connection: keep-alive
Server: ECS (sjc/16DF)
Vary: Accept-Encoding
X-Cache: HIT
<!doctype html>
<html>
<head>
<title>Example Domain</title>
// 省略...
</body>
</html>
```
## URL
2019-04-25 18:24:51 +08:00
2020-11-03 02:25:47 +08:00
http 使用 URL **U** niform **R**esource **L**ocator统一资源定位符来定位资源它可以认为是是 URI**U**niform **R**esource **I**dentifier统一资源标识符的一个子集URL URI 的基础上增加了定位能力URI 除了包含 URL 之外还包含 URNUniform Resource Name统一资源名称它知识用来定义一个资源的名称并不具备定位该资源的能力例如 urn:isbn:0451450523 用来定义一个书籍但是却没有表示怎么找到这本书
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/8441b2c4-dca7-4d6b-8efb-f22efccaf331.png" width="500px"> </div><br>
- [wikipedia统一资源标志符](https://zh.wikipedia.org/wiki/统一资源标志符)
- [wikipedia: URL](https://en.wikipedia.org/wiki/URL)
- [rfc26163.2.2 http URL](https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.2.2)
- [What is the difference between a URI, a URL and a URN?](https://stackoverflow.com/questions/176264/what-is-the-difference-between-a-uri-a-url-and-a-urn)
2019-04-25 18:24:51 +08:00
# HTTP 方法
2019-11-02 12:07:41 +08:00
客户端发送的 **请求报文** 第一行为请求行包含了方法字段
2019-04-25 18:24:51 +08:00
## GET
> 获取资源
当前网络请求中绝大部分使用的是 GET 方法
## HEAD
> 获取报文首部
GET 方法类似但是不返回报文实体主体部分
主要用于确认 URL 的有效性以及资源更新的日期时间等
## POST
> 传输实体主体
POST 主要用来传输数据 GET 主要用来获取资源
更多 POST GET 的比较请见第九章
## PUT
> 上传文件
由于自身不带验证机制任何人都可以上传文件因此存在安全性问题一般不使用该方法
```html
PUT /new.html HTTP/1.1
Host: example.com
Content-type: text/html
Content-length: 16
<p>New File</p>
```
## PATCH
> 对资源进行部分修改
PUT 也可以用于修改资源但是只能完全替代原始资源PATCH 允许部分修改
```html
PATCH /file.txt HTTP/1.1
Host: www.example.com
Content-Type: application/example
If-Match: "e0023aa4e"
Content-Length: 100
[description of changes]
```
## DELETE
> 删除文件
PUT 功能相反并且同样不带验证机制
```html
DELETE /file.html HTTP/1.1
```
## OPTIONS
> 查询支持的方法
查询指定的 URL 能够支持的方法
会返回 `Allow: GET, POST, HEAD, OPTIONS` 这样的内容
## CONNECT
> 要求在与代理服务器通信时建立隧道
使用 SSLSecure Sockets Layer安全套接层 TLSTransport Layer Security传输层安全协议把通信内容加密后经网络隧道传输
```html
CONNECT www.example.com:443 HTTP/1.1
```
2019-12-06 10:11:23 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/dc00f70e-c5c8-4d20-baf1-2d70014a97e3.jpg" width=""/> </div><br>
2019-04-25 18:24:51 +08:00
## TRACE
> 追踪路径
服务器会将通信路径返回给客户端
发送请求时 Max-Forwards 首部字段中填入数值每经过一个服务器就会减 1当数值为 0 时就停止传输
通常不会使用 TRACE并且它容易受到 XST 攻击Cross-Site Tracing跨站追踪
2020-11-03 02:25:47 +08:00
- [rfc26169 Method Definitions](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html)
2019-04-25 18:24:51 +08:00
# HTTP 状态码
2019-11-02 12:07:41 +08:00
服务器返回的 **响应报文** 中第一行为状态行包含了状态码以及原因短语用来告知客户端请求的结果
2019-04-25 18:24:51 +08:00
| 状态码 | 类别 | 含义 |
| :---: | :---: | :---: |
| 1XX | Informational信息性状态码 | 接收的请求正在处理 |
| 2XX | Success成功状态码 | 请求正常处理完毕 |
| 3XX | Redirection重定向状态码 | 需要进行附加操作以完成请求 |
| 4XX | Client Error客户端错误状态码 | 服务器无法处理请求 |
| 5XX | Server Error服务器错误状态码 | 服务器处理请求出错 |
## 1XX 信息
2019-11-02 12:07:41 +08:00
- **100 Continue** 表明到目前为止都很正常客户端可以继续发送请求或者忽略这个响应
2019-04-25 18:24:51 +08:00
## 2XX 成功
2019-11-02 12:07:41 +08:00
- **200 OK**
2019-04-25 18:24:51 +08:00
2019-11-02 12:07:41 +08:00
- **204 No Content** 请求已经成功处理但是返回的响应报文不包含实体的主体部分一般在只需要从客户端往服务器发送信息而不需要返回数据时使用
2019-04-25 18:24:51 +08:00
2019-11-02 12:07:41 +08:00
- **206 Partial Content** 表示客户端进行了范围请求响应报文包含由 Content-Range 指定范围的实体内容
2019-04-25 18:24:51 +08:00
## 3XX 重定向
2019-11-02 12:07:41 +08:00
- **301 Moved Permanently** 永久性重定向
2019-04-25 18:24:51 +08:00
2019-11-02 12:07:41 +08:00
- **302 Found** 临时性重定向
2019-04-25 18:24:51 +08:00
2019-11-02 12:07:41 +08:00
- **303 See Other** 302 有着相同的功能但是 303 明确要求客户端应该采用 GET 方法获取资源
2019-04-25 18:24:51 +08:00
- 虽然 HTTP 协议规定 301302 状态下重定向时不允许把 POST 方法改成 GET 方法但是大多数浏览器都会在 301302 303 状态下的重定向把 POST 方法改成 GET 方法
2019-11-02 12:07:41 +08:00
- **304 Not Modified** 如果请求报文首部包含一些条件例如If-MatchIf-Modified-SinceIf-None-MatchIf-RangeIf-Unmodified-Since如果不满足条件则服务器会返回 304 状态码
2019-04-25 18:24:51 +08:00
2019-11-02 12:07:41 +08:00
- **307 Temporary Redirect** 临时重定向 302 的含义类似但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法
2019-04-25 18:24:51 +08:00
## 4XX 客户端错误
2019-11-02 12:07:41 +08:00
- **400 Bad Request** 请求报文中存在语法错误
2019-04-25 18:24:51 +08:00
2019-11-02 12:07:41 +08:00
- **401 Unauthorized** 该状态码表示发送的请求需要有认证信息BASIC 认证DIGEST 认证如果之前已进行过一次请求则表示用户认证失败
2019-04-25 18:24:51 +08:00
2019-11-02 12:07:41 +08:00
- **403 Forbidden** 请求被拒绝
2019-04-25 18:24:51 +08:00
2019-11-02 12:07:41 +08:00
- **404 Not Found**
2019-04-25 18:24:51 +08:00
## 5XX 服务器错误
2019-11-02 12:07:41 +08:00
- **500 Internal Server Error** 服务器正在执行请求时发生错误
2019-04-25 18:24:51 +08:00
2019-11-02 12:07:41 +08:00
- **503 Service Unavailable** 服务器暂时处于超负载或正在进行停机维护现在无法处理请求
2019-04-25 18:24:51 +08:00
# 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 | 资源的最后修改日期时间 |
# 具体应用
## 连接管理
2019-12-06 10:11:23 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/HTTP1_x_Connections.png" width="800"/> </div><br>
2019-04-25 18:24:51 +08:00
### 1. 短连接与长连接
2019-05-03 23:16:09 +08:00
当浏览器访问一个包含多张图片的 HTML 页面时除了请求访问的 HTML 页面资源还会请求图片资源如果每进行一次 HTTP 通信就要新建一个 TCP 连接那么开销会很大
2019-04-25 18:24:51 +08:00
长连接只需要建立一次 TCP 连接就能进行多次 HTTP 通信
- HTTP/1.1 开始默认是长连接的如果要断开连接需要由客户端或者服务器端提出断开使用 `Connection : close`
- HTTP/1.1 之前默认是短连接的如果需要使用长连接则使用 `Connection : Keep-Alive`
### 2. 流水线
2019-05-03 23:16:09 +08:00
默认情况下HTTP 请求是按顺序发出的下一个请求只有在当前请求收到响应之后才会被发出由于受到网络延迟和带宽的限制在下一个请求被发送到服务器之前可能需要等待很长时间
2019-04-25 18:24:51 +08:00
2019-05-03 23:16:09 +08:00
流水线是在同一条长连接上连续发出请求而不用等待响应返回这样可以减少延迟
2019-04-25 18:24:51 +08:00
## Cookie
HTTP 协议是无状态的主要是为了让 HTTP 协议尽可能简单使得它能够处理大量事务HTTP/1.1 引入 Cookie 来保存状态信息
Cookie 是服务器发送到用户浏览器并保存在本地的一小块数据它会在浏览器之后向同一服务器再次发起请求时被携带上用于告知服务端两个请求是否来自同一浏览器由于之后每次请求都会需要携带 Cookie 数据因此会带来额外的性能开销尤其是在移动环境下
Cookie 曾一度用于客户端数据的存储因为当时并没有其它合适的存储办法而作为唯一的存储手段但现在随着现代浏览器开始支持各种各样的存储方式Cookie 渐渐被淘汰新的浏览器 API 已经允许开发者直接将数据存储到本地如使用 Web storage API本地存储和会话存储 IndexedDB
### 1. 用途
- 会话状态管理如用户登录状态购物车游戏分数或其它需要记录的信息
- 个性化设置如用户自定义设置主题等
- 浏览器行为跟踪如跟踪分析用户行为等
### 2. 创建过程
服务器发送的响应报文包含 Set-Cookie 首部字段客户端得到响应报文后把 Cookie 内容保存到浏览器中
```html
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry
[page content]
```
客户端之后对同一个服务器发送请求时会从浏览器中取出 Cookie 信息并通过 Cookie 请求首部字段发送给服务器
```html
GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry
```
### 3. 分类
- 会话期 Cookie浏览器关闭之后它会被自动删除也就是说它仅在会话期内有效
2019-05-03 23:16:09 +08:00
- 持久性 Cookie指定过期时间Expires或有效期max-age之后就成为了持久性的 Cookie
2019-04-25 18:24:51 +08:00
```html
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
```
### 4. 作用域
Domain 标识指定了哪些主机可以接受 Cookie如果不指定默认为当前文档的主机不包含子域名如果指定了 Domain则一般包含子域名例如如果设置 Domain=mozilla.org Cookie 也包含在子域名中 developer.mozilla.org
Path 标识指定了主机下的哪些路径可以接受 Cookie URL 路径必须存在于请求 URL 以字符 %x2F ("/") 作为路径分隔符子路径也会被匹配例如设置 Path=/docs则以下地址都会匹配
- /docs
- /docs/Web/
- /docs/Web/HTTP
### 5. JavaScript
2019-05-03 23:16:09 +08:00
浏览器通过 `document.cookie` 属性可创建新的 Cookie也可通过该属性访问非 HttpOnly 标记的 Cookie
2019-04-25 18:24:51 +08:00
```html
document.cookie = "yummy_cookie=choco";
document.cookie = "tasty_cookie=strawberry";
console.log(document.cookie);
```
### 6. HttpOnly
标记为 HttpOnly Cookie 不能被 JavaScript 脚本调用跨站脚本攻击 (XSS) 常常使用 JavaScript `document.cookie` API 窃取用户的 Cookie 信息因此使用 HttpOnly 标记可以在一定程度上避免 XSS 攻击
```html
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly
```
### 7. Secure
标记为 Secure Cookie 只能通过被 HTTPS 协议加密过的请求发送给服务端但即便设置了 Secure 标记敏感信息也不应该通过 Cookie 传输因为 Cookie 有其固有的不安全性Secure 标记也无法提供确实的安全保障
### 8. Session
除了可以将用户信息通过 Cookie 存储在用户浏览器中也可以利用 Session 存储在服务器端存储在服务器端的信息更加安全
Session 可以存储在服务器上的文件数据库或者内存中也可以将 Session 存储在 Redis 这种内存型数据库中效率会更高
使用 Session 维护用户登录状态的过程如下
- 用户进行登录时用户提交包含用户名和密码的表单放入 HTTP 请求报文中
- 服务器验证该用户名和密码如果正确则把用户信息存储到 Redis 它在 Redis 中的 Key 称为 Session ID
- 服务器返回的响应报文的 Set-Cookie 首部字段包含了这个 Session ID客户端收到响应报文之后将该 Cookie 值存入浏览器中
- 客户端之后对同一个服务器进行请求时会包含该 Cookie 服务器收到之后提取出 Session ID Redis 中取出用户信息继续之前的业务操作
应该注意 Session ID 的安全性问题不能让它被恶意攻击者轻易获取那么就不能产生一个容易被猜到的 Session ID 此外还需要经常重新生成 Session ID在对安全性要求极高的场景下例如转账等操作除了使用 Session 管理用户状态之外还需要对用户进行重新验证比如重新输入密码或者使用短信验证码等方式
### 9. 浏览器禁用 Cookie
此时无法使用 Cookie 来保存用户信息只能使用 Session除此之外不能再将 Session ID 存放到 Cookie 而是使用 URL 重写技术 Session ID 作为 URL 的参数进行传递
### 10. Cookie Session 选择
2019-05-03 23:16:09 +08:00
- Cookie 只能存储 ASCII 码字符串 Session 则可以存储任何类型的数据因此在考虑数据复杂性时首选 Session
2019-04-25 18:24:51 +08:00
- Cookie 存储在浏览器中容易被恶意查看如果非要将一些隐私数据存在 Cookie 可以将 Cookie 值进行加密然后在服务器进行解密
- 对于大型网站如果用户所有的信息都存储在 Session 那么开销是非常大的因此不建议将所有的用户信息都存储到 Session
## 缓存
### 1. 优点
- 缓解服务器压力
2019-05-03 23:16:09 +08:00
- 降低客户端获取资源的延迟缓存通常位于内存中读取缓存的速度更快并且缓存服务器在地理位置上也有可能比源服务器来得近例如浏览器缓存
2019-04-25 18:24:51 +08:00
### 2. 实现方法
- 让代理服务器进行缓存
- 让客户端浏览器进行缓存
### 3. Cache-Control
HTTP/1.1 通过 Cache-Control 首部字段来控制缓存
2019-11-02 12:07:41 +08:00
**3.1 禁止进行缓存**
2019-04-25 18:24:51 +08:00
no-store 指令规定不能对请求或响应的任何一部分进行缓存
```html
Cache-Control: no-store
```
2019-11-02 12:07:41 +08:00
**3.2 强制确认缓存**
2019-04-25 18:24:51 +08:00
2019-05-03 23:16:09 +08:00
no-cache 指令规定缓存服务器需要先向源服务器验证缓存资源的有效性只有当缓存资源有效时才能使用该缓存对客户端的请求进行响应
2019-04-25 18:24:51 +08:00
```html
Cache-Control: no-cache
```
2019-11-02 12:07:41 +08:00
**3.3 私有缓存和公共缓存**
2019-04-25 18:24:51 +08:00
2019-05-03 23:16:09 +08:00
private 指令规定了将资源作为私有缓存只能被单独用户使用一般存储在用户浏览器中
2019-04-25 18:24:51 +08:00
```html
Cache-Control: private
```
2019-05-03 23:16:09 +08:00
public 指令规定了将资源作为公共缓存可以被多个用户使用一般存储在代理服务器中
2019-04-25 18:24:51 +08:00
```html
Cache-Control: public
```
2019-11-02 12:07:41 +08:00
**3.4 缓存过期机制**
2019-04-25 18:24:51 +08:00
2019-05-03 23:16:09 +08:00
max-age 指令出现在请求报文并且缓存资源的缓存时间小于该指令指定的时间那么就能接受该缓存
2019-04-25 18:24:51 +08:00
2019-05-03 23:16:09 +08:00
max-age 指令出现在响应报文表示缓存资源在缓存服务器中保存的时间
2019-04-25 18:24:51 +08:00
```html
Cache-Control: max-age=31536000
```
Expires 首部字段也可以用于告知缓存服务器该资源什么时候会过期
```html
Expires: Wed, 04 Jul 2012 08:26:05 GMT
```
- HTTP/1.1 会优先处理 max-age 指令
- HTTP/1.0 max-age 指令会被忽略掉
### 4. 缓存验证
需要先了解 ETag 首部字段的含义它是资源的唯一标识URL 不能唯一表示资源例如 `http://www.google.com/` 有中文和英文两个资源,只有 ETag 才能对这两个资源进行唯一标识。
```html
ETag: "82e22293907ce725faf67773957acd12"
```
可以将缓存资源的 ETag 值放入 If-None-Match 首部服务器收到该请求后判断缓存资源的 ETag 值和资源的最新 ETag 值是否一致如果一致则表示缓存资源有效返回 304 Not Modified
```html
If-None-Match: "82e22293907ce725faf67773957acd12"
```
2019-05-03 23:16:09 +08:00
Last-Modified 首部字段也可以用于缓存验证它包含在源服务器发送的响应报文中指示源服务器对资源的最后修改时间但是它是一种弱校验器因为只能精确到一秒所以它通常作为 ETag 的备用方案如果响应首部字段里含有这个信息客户端可以在后续的请求中带上 If-Modified-Since 来验证缓存服务器只在所请求的资源在给定的日期时间之后对内容进行过修改的情况下才会将资源返回状态码为 200 OK如果请求的资源从那时起未经修改那么返回一个不带有实体主体的 304 Not Modified 响应报文
2019-04-25 18:24:51 +08:00
```html
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT
```
```html
If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT
```
## 内容协商
通过内容协商返回最合适的内容例如根据浏览器的默认语言选择返回中文界面还是英文界面
### 1. 类型
2019-11-02 12:07:41 +08:00
**1.1 服务端驱动型**
2019-04-25 18:24:51 +08:00
客户端设置特定的 HTTP 首部字段例如 AcceptAccept-CharsetAccept-EncodingAccept-Language服务器根据这些字段返回特定的资源
它存在以下问题
- 服务器很难知道客户端浏览器的全部信息
- 客户端提供的信息相当冗长HTTP/2 协议的首部压缩机制缓解了这个问题并且存在隐私风险HTTP 指纹识别技术
- 给定的资源需要返回不同的展现形式共享缓存的效率会降低而服务器端的实现会越来越复杂
2019-11-02 12:07:41 +08:00
**1.2 代理驱动型**
2019-04-25 18:24:51 +08:00
服务器返回 300 Multiple Choices 或者 406 Not Acceptable客户端从中选出最合适的那个资源
### 2. Vary
```html
Vary: Accept-Language
```
在使用内容协商的情况下只有当缓存服务器中的缓存满足内容协商条件时才能使用该缓存否则应该向源服务器请求该资源
例如一个客户端发送了一个包含 Accept-Language 首部字段的请求之后源服务器返回的响应包含 `Vary: Accept-Language` 内容缓存服务器对这个响应进行缓存之后在客户端下一次访问同一个 URL 资源并且 Accept-Language 与缓存中的对应的值相同时才会返回该缓存
## 内容编码
内容编码将实体主体进行压缩从而减少传输的数据量
常用的内容编码有gzipcompressdeflateidentity
2019-05-03 23:16:09 +08:00
浏览器发送 Accept-Encoding 首部其中包含有它所支持的压缩算法以及各自的优先级服务器则从中选择一种使用该算法对响应的消息主体进行压缩并且发送 Content-Encoding 首部来告知浏览器它选择了哪一种算法由于该内容协商过程是基于编码类型来选择资源的展现形式的响应报文的 Vary 首部字段至少要包含 Content-Encoding
2019-04-25 18:24:51 +08:00
## 范围请求
如果网络出现中断服务器只发送了一部分数据范围请求可以使得客户端只请求服务器未发送的那部分数据从而避免服务器重新发送所有数据
### 1. Range
在请求报文中添加 Range 首部字段指定请求的范围
```html
GET /z4d4kWk.jpg HTTP/1.1
Host: i.imgur.com
Range: bytes=0-1023
```
请求成功的话服务器返回的响应包含 206 Partial Content 状态码
```html
HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1023/146515
Content-Length: 1024
...
(binary content)
```
### 2. Accept-Ranges
响应首部字段 Accept-Ranges 用于告知客户端是否能处理范围请求可以处理使用 bytes否则使用 none
```html
Accept-Ranges: bytes
```
### 3. 响应状态码
- 在请求成功的情况下服务器会返回 206 Partial Content 状态码
- 在请求的范围越界的情况下服务器会返回 416 Requested Range Not Satisfiable 状态码
- 在不支持范围请求的情况下服务器会返回 200 OK 状态码
## 分块传输编码
Chunked Transfer Encoding可以把数据分割成多块让浏览器逐步显示页面
## 多部分对象集合
一份报文主体内可含有多种类型的实体同时发送每个部分之间用 boundary 字段定义的分隔符进行分隔每个部分都可以有首部字段
例如上传多个表单时可以使用如下方式
```html
Content-Type: multipart/form-data; boundary=AaB03x
--AaB03x
Content-Disposition: form-data; name="submit-name"
Larry
--AaB03x
Content-Disposition: form-data; name="files"; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--AaB03x--
```
## 虚拟主机
HTTP/1.1 使用虚拟主机技术使得一台服务器拥有多个域名并且在逻辑上可以看成多个服务器
## 通信数据转发
### 1. 代理
代理服务器接受客户端的请求并且转发给其它服务器
使用代理的主要目的是
- 缓存
- 负载均衡
- 网络访问控制
- 访问日志记录
代理服务器分为正向代理和反向代理两种
- 用户察觉得到正向代理的存在
2019-12-06 10:11:23 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/a314bb79-5b18-4e63-a976-3448bffa6f1b.png" width=""/> </div><br>
2019-04-25 18:24:51 +08:00
- 而反向代理一般位于内部网络中用户察觉不到
2019-12-06 10:11:23 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/2d09a847-b854-439c-9198-b29c65810944.png" width=""/> </div><br>
2019-04-25 18:24:51 +08:00
### 2. 网关
与代理服务器不同的是网关服务器会将 HTTP 转化为其它协议进行通信从而请求其它非 HTTP 服务器的服务
### 3. 隧道
使用 SSL 等加密手段在客户端和服务器之间建立一条安全的通信线路
# HTTPS
HTTP 有以下安全性问题
- 使用明文进行通信内容可能会被窃听
- 不验证通信方的身份通信方的身份有可能遭遇伪装
- 无法证明报文的完整性报文有可能遭篡改
HTTPS 并不是新协议而是让 HTTP 先和 SSLSecure Sockets Layer通信再由 SSL TCP 通信也就是说 HTTPS 使用了隧道进行通信
通过使用 SSLHTTPS 具有了加密防窃听认证防伪装和完整性保护防篡改
2019-12-06 10:11:23 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/ssl-offloading.jpg" width="700"/> </div><br>
2019-04-25 18:24:51 +08:00
## 加密
### 1. 对称密钥加密
对称密钥加密Symmetric-Key Encryption加密和解密使用同一密钥
- 优点运算速度快
- 缺点无法安全地将密钥传输给通信方
2019-12-06 10:11:23 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/7fffa4b8-b36d-471f-ad0c-a88ee763bb76.png" width="600"/> </div><br>
2019-04-25 18:24:51 +08:00
### 2.非对称密钥加密
非对称密钥加密又称公开密钥加密Public-Key Encryption加密和解密使用不同的密钥
公开密钥所有人都可以获得通信发送方获得接收方的公开密钥之后就可以使用公开密钥进行加密接收方收到通信内容后使用私有密钥解密
非对称密钥除了用来加密还可以用来进行签名因为私有密钥无法被其他人获取因此通信发送方使用其私有密钥进行签名通信接收方使用发送方的公开密钥对签名进行解密就能判断这个签名是否正确
- 优点可以更安全地将公开密钥传输给通信发送方
- 缺点运算速度慢
2019-12-06 10:11:23 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/39ccb299-ee99-4dd1-b8b4-2f9ec9495cb4.png" width="600"/> </div><br>
2019-04-25 18:24:51 +08:00
### 3. HTTPS 采用的加密方式
2019-12-05 01:47:57 +08:00
上面提到对称密钥加密方式的传输效率更高但是无法安全地将密钥 Secret Key 传输给通信方而非对称密钥加密方式可以保证传输的安全性因此我们可以利用非对称密钥加密方式将 Secret Key 传输给通信方HTTPS 采用混合的加密机制正是利用了上面提到的方案
- 使用非对称密钥加密方式传输对称密钥加密方式所需要的 Secret Key从而保证安全性;
- 获取到 Secret Key 再使用对称密钥加密方式进行通信从而保证效率下图中的 Session Key 就是 Secret Key
2019-04-25 18:24:51 +08:00
2019-12-06 10:11:23 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/How-HTTPS-Works.png" width="600"/> </div><br>
2019-04-25 18:24:51 +08:00
## 认证
2019-11-02 12:07:41 +08:00
通过使用 **证书** 来对通信方进行认证
2019-04-25 18:24:51 +08:00
数字证书认证机构CACertificate Authority是客户端与服务器双方都可信赖的第三方机构
服务器的运营人员向 CA 提出公开密钥的申请CA 在判明提出申请者的身份之后会对已申请的公开密钥做数字签名然后分配这个已签名的公开密钥并将该公开密钥放入公开密钥证书后绑定在一起
进行 HTTPS 通信时服务器会把证书发送给客户端客户端取得其中的公开密钥之后先使用数字签名进行验证如果验证通过就可以开始通信了
2019-12-06 10:11:23 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/2017-06-11-ca.png" width=""/> </div><br>
2019-04-25 18:24:51 +08:00
## 完整性保护
SSL 提供报文摘要功能来进行完整性保护
HTTP 也提供了 MD5 报文摘要功能但不是安全的例如报文内容被篡改之后同时重新计算 MD5 的值通信接收方是无法意识到发生了篡改
HTTPS 的报文摘要功能之所以安全是因为它结合了加密和认证这两个操作试想一下加密之后的报文遭到篡改之后也很难重新计算报文摘要因为无法轻易获取明文
## HTTPS 的缺点
- 因为需要进行加密解密等过程因此速度会更慢
- 需要支付证书授权的高额费用
# HTTP/2.0
## HTTP/1.x 缺陷
HTTP/1.x 实现简单是以牺牲性能为代价的
- 客户端需要使用多个连接才能实现并发和缩短延迟
- 不会压缩请求和响应首部从而导致不必要的网络流量
- 不支持有效的资源优先级致使底层 TCP 连接的利用率低下
## 二进制分帧层
HTTP/2.0 将报文分成 HEADERS 帧和 DATA 它们都是二进制格式的
2019-12-06 10:11:23 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/86e6a91d-a285-447a-9345-c5484b8d0c47.png" width="400"/> </div><br>
2019-04-25 18:24:51 +08:00
在通信过程中只会有一个 TCP 连接存在它承载了任意数量的双向数据流Stream
- 一个数据流Stream都有一个唯一标识符和可选的优先级信息用于承载双向信息
- 消息Message是与逻辑请求或响应对应的完整的一系列帧
- Frame是最小的通信单位来自不同数据流的帧可以交错发送然后再根据每个帧头的数据流标识符重新组装
2019-12-06 10:11:23 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/af198da1-2480-4043-b07f-a3b91a88b815.png" width="600"/> </div><br>
2019-04-25 18:24:51 +08:00
## 服务端推送
HTTP/2.0 在客户端请求一个资源时会把相关的资源一起发送给客户端客户端就不需要再次发起请求了例如客户端请求 page.html 页面服务端就把 script.js style.css 等与之相关的资源一起发给客户端
2019-12-06 10:11:23 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e3f1657c-80fc-4dfa-9643-bf51abd201c6.png" width="800"/> </div><br>
2019-04-25 18:24:51 +08:00
## 首部压缩
HTTP/1.1 的首部带有大量信息而且每次都要重复发送
HTTP/2.0 要求客户端和服务器同时维护和更新一个包含之前见过的首部字段表从而避免了重复传输
不仅如此HTTP/2.0 也使用 Huffman 编码对首部字段进行压缩
2019-12-06 10:11:23 +08:00
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/_u4E0B_u8F7D.png" width="600"/> </div><br>
2019-04-25 18:24:51 +08:00
# HTTP/1.1 新特性
详细内容请见上文
- 默认是长连接
- 支持流水线
- 支持同时打开多个 TCP 连接
- 支持虚拟主机
- 新增状态码 100
- 支持分块传输编码
- 新增缓存处理指令 max-age
# GET POST 比较
## 作用
GET 用于获取资源 POST 用于传输实体主体
## 参数
GET POST 的请求都能使用额外的参数但是 GET 的参数是以查询字符串出现在 URL POST 的参数存储在实体主体中不能因为 POST 参数存储在实体主体中就认为它的安全性更高因为照样可以通过一些抓包工具Fiddler查看
因为 URL 只支持 ASCII 因此 GET 的参数中如果存在中文等字符就需要先进行编码例如 `中文` 会转换为 `%E4%B8%AD%E6%96%87`而空格会转换为 `%20`POST 参数支持标准字符集
```
GET /test/demo_form.asp?name1=value1&name2=value2 HTTP/1.1
```
```
POST /test/demo_form.asp HTTP/1.1
Host: w3schools.com
name1=value1&name2=value2
```
## 安全
安全的 HTTP 方法不会改变服务器状态也就是说它只是可读的
GET 方法是安全的 POST 却不是因为 POST 的目的是传送实体主体内容这个内容可能是用户上传的表单数据上传成功之后服务器可能把这个数据存储到数据库中因此状态也就发生了改变
安全的方法除了 GET 之外还有HEADOPTIONS
不安全的方法除了 POST 之外还有 PUTDELETE
## 幂等性
幂等的 HTTP 方法同样的请求被执行一次与连续执行多次的效果是一样的服务器的状态也是一样的换句话说就是幂等方法不应该具有副作用统计用途除外
所有的安全方法也都是幂等的
在正确实现的条件下GETHEADPUT DELETE 等方法都是幂等的 POST 方法不是
GET /pageX HTTP/1.1 是幂等的连续调用多次客户端接收到的结果都是一样的
```
GET /pageX HTTP/1.1
GET /pageX HTTP/1.1
GET /pageX HTTP/1.1
GET /pageX HTTP/1.1
```
POST /add_row HTTP/1.1 不是幂等的如果调用多次就会增加多行记录
```
POST /add_row HTTP/1.1 -> Adds a 1nd row
POST /add_row HTTP/1.1 -> Adds a 2nd row
POST /add_row HTTP/1.1 -> Adds a 3rd row
```
2019-05-03 23:23:06 +08:00
DELETE /idX/delete HTTP/1.1 是幂等的即使不同的请求接收到的状态码不一样
2019-04-25 18:24:51 +08:00
```
DELETE /idX/delete HTTP/1.1 -> Returns 200 if idX exists
DELETE /idX/delete HTTP/1.1 -> Returns 404 as it just got deleted
DELETE /idX/delete HTTP/1.1 -> Returns 404
```
## 可缓存
如果要对响应进行缓存需要满足以下条件
- 请求报文的 HTTP 方法本身是可缓存的包括 GET HEAD但是 PUT DELETE 不可缓存POST 在多数情况下不可缓存的
- 响应报文的状态码是可缓存的包括200, 203, 204, 206, 300, 301, 404, 405, 410, 414, and 501
- 响应报文的 Cache-Control 首部字段没有指定不进行缓存
## XMLHttpRequest
为了阐述 POST GET 的另一个区别需要先了解 XMLHttpRequest
> XMLHttpRequest 是一个 API它为客户端提供了在客户端和服务器之间传输数据的功能它提供了一个通过 URL 来获取数据的简单方式并且不会使整个页面刷新这使得网页只更新一部分页面而不会打扰到用户XMLHttpRequest AJAX 中被大量使用
- 在使用 XMLHttpRequest POST 方法时浏览器会先发送 Header 再发送 Data但并不是所有浏览器会这么做例如火狐就不会
- GET 方法 Header Data 会一起发送
# 参考资料
- 上野宣. 图解 HTTP[M]. 人民邮电出版社, 2014.
- [MDN : HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP)
- [HTTP/2 简介](https://developers.google.com/web/fundamentals/performance/http2/?hl=zh-cn)
- [htmlspecialchars](http://php.net/manual/zh/function.htmlspecialchars.php)
- [Difference between file URI and URL in java](http://java2db.com/java-io/how-to-get-and-the-difference-between-file-uri-and-url-in-java)
- [How to Fix SQL Injection Using Java PreparedStatement & CallableStatement](https://software-security.sans.org/developer-how-to/fix-sql-injection-in-java-using-prepared-callable-statement)
- [浅谈 HTTP Get Post 的区别](https://www.cnblogs.com/hyddd/archive/2009/03/31/1426026.html)
- [Are http:// and www really necessary?](https://www.webdancers.com/are-http-and-www-necesary/)
- [HTTP (HyperText Transfer Protocol)](https://www.ntu.edu.sg/home/ehchua/programming/webprogramming/HTTP_Basics.html)
- [Web-VPN: Secure Proxies with SPDY & Chrome](https://www.igvita.com/2011/12/01/web-vpn-secure-proxies-with-spdy-chrome/)
- [File:HTTP persistent connection.svg](http://en.wikipedia.org/wiki/File:HTTP_persistent_connection.svg)
- [Proxy server](https://en.wikipedia.org/wiki/Proxy_server)
- [What Is This HTTPS/SSL Thing And Why Should You Care?](https://www.x-cart.com/blog/what-is-https-and-ssl.html)
- [What is SSL Offloading?](https://securebox.comodo.com/ssl-sniffing/ssl-offloading/)
- [Sun Directory Server Enterprise Edition 7.0 Reference - Key Encryption](https://docs.oracle.com/cd/E19424-01/820-4811/6ng8i26bn/index.html)
- [An Introduction to Mutual SSL Authentication](https://www.codeproject.com/Articles/326574/An-Introduction-to-Mutual-SSL-Authentication)
- [The Difference Between URLs and URIs](https://danielmiessler.com/study/url-uri/)
- [Cookie Session 的区别](https://juejin.im/entry/5766c29d6be3ff006a31b84e#comment)
- [COOKIE SESSION 有什么区别](https://www.zhihu.com/question/19786827)
- [Cookie/Session 的机制与安全](https://harttle.land/2015/08/10/cookie-session.html)
- [HTTPS 证书原理](https://shijianan.com/2017/06/11/https/)
- [What is the difference between a URI, a URL and a URN?](https://stackoverflow.com/questions/176264/what-is-the-difference-between-a-uri-a-url-and-a-urn)
- [XMLHttpRequest](https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest)
- [XMLHttpRequest (XHR) Uses Multiple Packets for HTTP POST?](https://blog.josephscott.org/2009/08/27/xmlhttprequest-xhr-uses-multiple-packets-for-http-post/)
- [Symmetric vs. Asymmetric Encryption What are differences?](https://www.ssl2buy.com/wiki/symmetric-vs-asymmetric-encryption-what-are-differences)
- [Web 性能优化与 HTTP/2](https://www.kancloud.cn/digest/web-performance-http2)
- [HTTP/2 简介](https://developers.google.com/web/fundamentals/performance/http2/?hl=zh-cn)
2019-10-28 00:25:00 +08:00
2019-11-02 17:33:10 +08:00
<div align="center"><img width="320px" src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/githubio/公众号二维码-2.png"></img></div>