HTTP协议
本文最后更新于:2022年6月1日 下午
HTTP(HyperText Transfer Protocol,超文本传输协议
HTTP 是基于 TCP/IP 协议的应用层协议,用于客户端和服务器之间的通信
链路层,网络层,传输层,应用层
HTTP 报文组成部分
请求报文
- 请求行
Request Method
,Request URL
- 请求头 包含若干属性,key:value 值
- 空行
- 请求体
- 请求行
响应报文
- 状态行
Request Version
,Status Code
- 响应头 包含若干属性,key:value 值
- 空行
- 响应体
- 状态行
字段
缓存相关
-
Cache-Control
-
Pragma
-
Expires
实体首部 -
Last-Modified
实体首部 -
If-Modified-Since
-
ETag
-
If-None-Match
-
Cookie 相关
-
Cookie
-
Set-Cookie
-
跨域相关
-
Origin
-
Access-Control-Request-Method
-
Access-Control-Allow-Origin
-
Access-Control-Allow-Methods
-
Access-Control-Max-Age
-
Access-Control-Allow-Credentials
-
请求来源
-
Connection
:keep-alive / close / upgrade -
Referer
请求来源域 Origin
请求来源域这个单词是错的
-
Host
服务器域名 -
Upgrade
:websocket
-
HTTP 的响应状态码
消息
- 100 继续发送
- 101 协议升级
请求成功
- 200 OK
- 206 处理了部分请求
重定向
- 301 永久性重定向,资源已经分配了新的 URl
- 302 临时重定向
- 303 表示资源存在着另一个 URL,应使用 GET 方法获取资源
对于 301/302/303 响应,几乎所有浏览器都会删除报文主体并自动用 GET 重新请求
- 304 资源未修改
请求错误
- 400 Bad Request 请求报文语法错误
- 401 Unauthorized 需要认证
- 403 Forbidden 禁止访问
- 404 Not Found
- 405 请求方法非法
- 408 请求超时
服务器错误
- 500 服务器错误
- 503 服务器过载
- 505 不支持该版本 HTTP 协议
HTTP 发展历程
HTTP 0.9
-
GET
- 只能且直接返回 html
HTTP1.0
串行连接:每次通信完后断开 TCP 通道,每个新请求都需要建立新的连接
GET
- 请求放在参数放在 URL 地址后
- 刷新无副作用
- 能保存书签,会被浏览器缓存,加入历史记录
- 编码 urlencoded
- 浏览器或者服务器会对 URL 长度做限制
POST
- 请求参数放在 body 中
- 刷新提示再次提交?
- 不缓存不保存不记录
- 数据类型无限制
HEAD
与 get 相同的请求,不过只请求头部,获取其中“关于该资源的信息”(元信息或称元数据)
HTTP1.1
持久连接:一定时间内,只要不是主动断开则保持连接(keep-alive 设定这个时长),但是下一个请求必须等待上一个请求响应完成(线头阻塞)
管线化持久连接:在同一条长连接上发出连续的请求,而不用等待应答返回,只能用于
GET
,HEAD
,PUT
,DELETE
请求OPTIONS
询问获取当前资源所支持的方法PUT
从客户端向服务器传送新文件PATCH
是对 PUT 方法的补充,用来对已知资源进行局部更新 。DELETE
请求服务器删除指定文件TRACE
回显服务器收到的请求,主要用于测试或诊断。CONNECT
HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。
SPDY
- 2009 年推出,试验性
- 位于 HTTP 与 SSl 之间,是对 HTTP 的增强
特性:
多路复用:通过一个 TCP 连接,可以无限制处理多个 HTTP 请求。
赋予请求优先级:给请求逐个分配优先级顺序。可以解决在发送多个请求时,因带宽低而导致响应变慢的问题。
压缩 HTTP 头部:压缩方式:DELEFT
服务端推送
SPDY 位于 HTTP 下,TCP 和 SSL 之上,可以兼容老版本 http 同时使用可用的 ssl 功能
SPDY 强制使用 SSL
HTTP2
2015 年发布,基于 SPDY 协议
http/1.x 是一个超文本协议,而 http2 是一个二进制协议
特性:
二进制分帧
当客户端同时向服务端发起多个请求,那么这些请求会被分解成一一个的帧,每个帧都会在一个 TCP 链路中无序的传输,当帧到达服务端之后,就可以根据
Stream Identifier
来重新组合得到完整的请求。头部压缩
- 请求和响应首部压缩
HPACK
算法,客户端和服务器建立字典(首部表)重复头部不用再发送
服务端推送
Server Push
- 服务端能主动返回多的觉得客户端会用到的资源
多路复用
- 同域名的通信都在单个连接上完成(只占用一个 tcp 连接
- 单连接可以承受任意数量的双向数据流
HTTP3
- http3 使用新的 UDP 协议
QUIC
代替 TCP - 解决 http2 时代丢包阻塞
- 切换网络时的连接保持(快速重启会话)
- 加密传输
HTTPS
TLS/SSl
传输层安全性协议(英语:Transport Layer Security,缩写作 TLS),及其前身安全套接层(Secure Sockets Layer,缩写作 SSL)是一种安全协议,目的是为互联网通信提供安全及数据完整性保障。
TLS 协议的特点是与应用层协议(HTTP,FTP)无耦合,应用层协议能透明运行在 TLS 协议上层(HTTP 与 TCP 之间)
概念
【非对称加密】
只有使用私钥才能解开公钥加密
【摘要算法】
输出固定长度的数据,用来计算数据指纹,比如 SHA256
【数字签名】
使用私钥对摘要算法得出的指纹加密
SSL 证书
- 证书包含以下信息:申请者公钥、申请者的组织信息和个人信息、签发机构 CA 的信息、有效时间、证书序列号,摘要算法等信息的明文
- CA 使用 CA 私钥对证书明文摘要算法后得出的指纹进行加密得到签名
浏览器验证证书合法性
- 从操作系统中找到相应的
CA机构证书
- 使用
CA证书
的公钥解密站点证书
的签名
得到校验码 1 - 使用证书制定的摘要算法对
站点证书
明文计算得到校验码 2 - 比较两个校验码相同则说明证书没被篡改
- 后面就开始查看证书是否在有效期,是否对应当前域名,是否在吊销列表中等
HTTPS 工作流程
- 用户访问:443,发送客户端支持的加密算法列表和随机数
Random_C
- 服务器根据支持的算法计算并返回证书和随机数
Random_S
- 用户浏览器使用操作系统里的 CA 公钥 打开并验证证书的合法性得到证书中的 服务器公钥
- 用户生成生新的随机数
Premaster secret
,并使用 服务器公钥 加密发送给服务器 - 服务器使用自己的 服务器私钥 解密,得到
Premaster secret
- 此后双方使用同样的加密算法对三个随机数进行计算得到对称的密钥
enc_key
- 至此双方得到了对称加密密钥,之后的连接都只使用对称加密
TCP 握手
三次握手
- 为了确保通信双方收发能力正常
- 指定自己的初始化序列号,为后面的可靠传送做准备
- 过程:
- 第一次握手:
客户端给服务端发一个SYN
报文,并指明客户端的初始化序列号ISN(c)
。此时客户端处于SYN_Send
状态。 - 第二次握手:
服务器收到客户端的SYN
报文之后,会以自己的SYN
报文作为应答,并且也是指定了自己的初始化序列号ISN(s)
,同时会把客户端的ISN(c) + 1
作为ACK(确认字符)
的值,表示自己已经收到了客户端的SYN
,此时服务器处于SYN_REVD
的状态。 - 第三次握手:
客户端收到SYN
报文之后,会发送一个ACK
报文,当然,也是一样把服务器的ISN(s) + 1
作为ACK
的值,表示已经收到了服务端的SYN
报文,此时客户端处于establised
状态。同时该 tcp 栈已经允许请求数据,例如可以同时带上一个 GET 请求
- 服务器收到 ACK 报文之后,也处于
establised
状态,此时,双方以建立起了链接。
- 第一次握手:
半连接队列
:在 TCP 协议三次握手的连接过程中,如果一个用户向服务器发送了 SYN 报文,服务器又发出 SYN+ACK 应答报文后未收到客户端的 ACK 报文回应,这种情况下服务器端会再次发送 SYN+ACK 给客户端,并等待一段时间后丢弃这个未完成的连接,这段时间的长度称为 SYN Timeout,一般来说这个时间是分钟级。
泛洪攻击
:SYN 泛洪攻击通过发送大量的伪造 TCP 连接报文而造成大量的 TCP 半连接,服务器端将为了维护这样一个庞大的半连接列表而消耗非常多的资源。这样服务器端将忙于处理攻击者伪造的 TCP 连接请求而无法处理正常连接请求,甚至会导致堆栈的溢出崩溃。
四次挥手
- 断开 tcp 连接
- 过程:
- 第一次挥手:
客户端发送FIN
报文,报文中会指定一个序列号SYN(c)
。此时客户端处于FIN_WAIT1
状态。 - 第二次握手:
服务端收到FIN
之后,会把客户端的序列号值SYN(c) + 1
作为ACK
报文的序列号值并发送给客户端,表明已经收到客户端的报文了,此时服务端处于CLOSE_WAIT
状态。 - 第三次挥手:
如果服务端也想断开连接了,和客户端的第一次挥手一样,发给FIN
报文,且指定一个序列号SYN(s)
。此时服务端处于LAST_ACK
的状态。 - 第四次挥手:
客户端收到 FIN 之后,也把服务端的序列号值SYN(s) + 1
作为自己ACK
报文的序列号值并发送给服务端,此时客户端处于TIME_WAIT
状态。之后才会进入CLOSED
状态 - 服务端收到
ACK
报文之后,就处于关闭连接了,处于CLOSED
状态。
- 第一次挥手:
TIME_WAIT
状态:客户端发送 ACK 之后不直接关闭,而是要等一阵子才关闭,确保服务器是否已经收到了 ACK 报文,如果没有收到的话,服务器会重新发 FIN 报文给客户端,客户端再次收到 ACK 报文之后,就知道之前的 ACK 报文丢失了,然后再次发送 ACK 报文。
也可缩短为三次挥手,上述二三步骤合并,服务器同时回复 ACK 和 FIN
Websocket
- websocket 的出现解决了传统 http 请求只能由客户端发起的缺陷
- http 无法得知服务器连续的状态变化,只能靠轮询
- ws 构造函数就要传入
绝对URL
,且连接不能转发只能是直接连接 - 全双工,双向通信
- 服务端推送
- 持久连接
- 基于 TCP 传输,复用 HTTP 的握手通道
- 协议升级为 ws
- 客户端请求
Connection: Upgrade; Upgrade: websocket;
- 服务端响应协议升级
HTTP/1.1 101 Switching Protocols
- 客户端请求