HTTP协议介绍
1. HTTP
HTTP
协议用于客户端和服务端之间的通信,通过请求和响应的交换达成通信。HTTP
本身是一种不保存状态的协议,即无状态协议,每当有新请求发送,就会对应着有响应的产生。
请求报文和响应报文的首部内容由以下数据组成:
- 请求行:包含请求方法、请求
URI
和HTTP
版本; - 状态行:包含表明响应结果的状态码、原因短语和
HTTP
版本; - 首部字段:包含表示请求和响应的各种条件和属性的各类首部,一般有四类首部:通用首部、请求首部、响应首部和实体首部;
- 其他:可能包含
HTTP
的RFC
里未定义的首部 ( 如Cookie
等 )。
HTTP
在传输数据时可以那招数据原貌直接传输,也可以在传输的过程中通过编码提升传输速率。报文 ( $message$ ) 是HTTP
通信中的基本单位,由字节流组成;实体 ( $entity$ ) 是请求或响应的有效载荷数据,由实体首部和实体主体组成。通常报文主体等于实体主体,只有当传输中进行编码操作时,实体主体的内容才会发生变化。
在传输大容量数据时,HTTP
允许将数据分割,这种功能称为分块传输编码 ( $Chunked\ \ Transfer\ \ Coding$ ),允许将实体主体分块,每块使用十六进制标记大小,最后一块会使用 $0(CR+LF)$ 标记。为了发送多种类型实体,HTTP
还采用了多部份对象集合,包含如下对象:$multipart/form-data$ 、$multipart/byteranges$ 。在使用时,需要在首部字段里加上 $Content-type$ 。
HTTP
通信时,除客户端和服务器以外,还有一些用于通信数据转发的应用程序,例如代理、网关和隧道。
- 代理:代理扮演了位于服务器和客户端的中间人的角色,接收请求和响应并进行转发。使用代理的理由有:利用缓存技术减少网络带宽流量,组织内部针对特定网站的访问控制,以获取访问日志为主要目的等;
- 网关是转发其他服务器通信数据的服务器,接收从客户端发送来的请求时,就像自己拥有资源的服务器一样处理。使用网关能提高通信的安全性;
- 隧道是在相隔甚远的客户端和服务器之间进行中转,并保持双方通信连接的应用程序。隧道的目的是确保客户端能与服务器进行安全的通信。
1.1 请求
GET /index.htm HTTP/1.1
Host: xxxx.com
起始行开头的 $GET$ 表示请求访问服务器的类型,称为方法。$/index.htm$ 是请求访问的资源对象,也叫做请求URI
( $Request\ \ URI$ ) 。最后的 $HTTP/1.1$ 即HTTP
版本号,指明客户端使用的HTTP
协议版本。
HTTP
使用URI
定位互联网上的资源,可以指定完整路径,也可以通过与 $Host$ 字段结合指定相对路径。如果不是访问特定资源而是对服务器本身发起请求,可以使用 $*$ 代替请求URI
,如下:
OPTIONS * HTTP/1.1
HTTP/1.1
中可使用的方法如下:
- $GET$ :请求访问已被
URI
识别的资源,经服务器段解析后返回响应内容; - $POST$ :请求访问已被
URI
识别的资源,数据被包含在请求体中,可能会导致新资源的创建和修改; - $PUT$ :传输文件,要求在请求报文主体中包含文件内容;
- $HEAD$ :与 $GET$ 一样,但不返回主体,只返回首部,用于确认
URI
有效性及资源更新的时间等; - $DELETE$ :删除文件;
- $OPTIONS$ :查询针对请求
URI
指定的资源的支持方法; - $TRACE$ :让
Web
服务器端将之前的请求通信环返回给客户端; - $CONNECT$ :在与代理服务器通信时建立隧道,通过隧道协议进行
TCP
通信,主要使用SSL
( $Secure\ \ Sockets\ \ Layer$ ,安全套接层 ) 和TLS
( $Transfer\ \ Layer\ \ Security$ ,传输层安全 ) 协议把通信内容加密后经网络隧道传输。
HTTP/1.1
中提供了持久连接 ( $HTTP\ \ Persistence\ \ Connections$ ,也称为 $HTTP\ \ keep-alive$ ),只要任意一端没有明确提出断开连接,则保持TCP
连接状态。持久连接使得多数请求以管道化 ( $pipelining$ ) 方式发送称为可能,即不用等待上一个请求的响应即可发送下一个请求。
作为无状态协议,在登录等场景需要保存状态,因此引入了Cookie
技术。Cookie
通过在请求和响应报文中写入Cookie
信息来控制客户端状态。根据从服务端发送的响应报文内一个叫做 $Set-Cookie$ 的首部字段信息,客户端会保存Cookie
,并在下次发送请求时自动在报文中加入Cookie
。
# 首次请求报文
GET /reader/ HTTP/1.1
Host: xxx.com
# 响应报文
HTTP/1.1 200 OK
Date: Thu, 12 Jul 2012 07:12:20 GMT
Server: Apache
Set-Cookie: sid=1342077140226724; path=/; expires=Wed, 10-Oct-12 07:12:20 GMT
Content-Type: text/plain; charset=UTF-8
# 第二次请求
GET /image/ HTTP/1.1
Host: xxx.com
Cookie: sid=1342077140226724
内容协商机制是指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最为适合的资源。请求报文中的某些首部字段就是判断基准:$Accept$ 、$Accept-Charset$ 、$Accept-Encoding$ 、$Accept-Language$ 、$Content-Language$ 。
1.2 响应
HTTP/1.1 200 OK
Date: Tue, 10 Jul 2012 06:50:15 GMT
Content-Length: 362
Content-Type: text/html
<html>
......
$HTTP/1.1$ 指明服务器使用的HTTP
版本,$200$ 表示请求的处理结果状态码 ( $status\ \ code$ ) 和原因短语 ( $reason-phrase$ ) 。下一行显示了创建响应的日期时间,是首部字段 ( $header\ \ field$ ) 内的一个属性。接下来是以一空行分开的资源实体的主体 ( $entity\ \ body$ )。
1.3 状态码
状态码 | 类别 | 原因短语 |
---|---|---|
$1XX$ | 信息性状态码 | 接收的请求正在处理 |
$2XX$ | 成功状态码 | 请求正常处理完毕 |
$3XX$ | 重定向状态码 | 需要进行附加操作以完成请求 |
$4XX$ | 客户端错误状态码 | 服务器无法处理请求 |
$5XX$ | 服务器错误状态码 | 服务器处理请求出错 |
状态码数量繁多,但实际上最常使用的只有 $15$ 种。
状态码 | 原因 |
---|---|
$200\ \ OK$ | 从客户端发来的请求被正常处理 |
$204\ \ No\ \ Content$ | 请求成功处理,但响应不包含实体主体,一般在不需要向客户端发送新内容时使用 |
$206\ \ Partial\ \ Content$ | 客户端进行范围请求,响应报文中包含 $Content-Range$ 指定范围的实体内容 |
$301\ \ Moved\ \ Permanently$ | 永久重定向,表示请求的资源已经被分配了新的URI |
$302\ \ Found$ | 临时重定向,已移动的资源可能还会再改变 |
$303\ \ See\ \ Other$ | 请求资源存在另一个URI ,使用 $GET$ 重新获取 |
$304\ \ Not\ \ Modified$ | 所请求的资源未修改,服务器不会返回任何资源 |
$307\ \ Temporary\ \ Redirect$ | 临时重定向,使用 $GET$ 或 $POST$ 获取 |
$400\ \ Bad\ \ Request$ | 请求报文存在语法错误 |
$401\ \ Unauthorized$ | 发送的请求需要有通过HTTP 认证的认证信息 |
$403\ \ Forbidden$ | 对请求资源访问被服务器拒绝,服务器没有必要给出详细理由 |
$404\ \ Not\ \ Found$ | 服务器上无法找到请求的资源 |
$500\ \ Internal\ \ Server\ \ Error$ | 服务器端在执行请求时发生错误 |
$502\ \ Bad\ \ Gateway$ | 作为网关或者代理尝试执行请求时从远程服务器接收到一个无效响应 |
$503\ \ Service\ \ Unavailable$ | 服务器暂时处于超负载或者正在进行停机维护 |
2. HTTPS
HTTP
虽然方便,但也存在不足:使用明文、不验证身份、无法证明报文的完整性。HTTP
协议中没有加密机制,但可以通过和SSL
或TLS
的组合使用,加密HTTP
的通信内容。与SSL
组合使用的HTTP
被称为HTTPS
( $HTTP\ \ Secure$ ) 或HTTP over SSL
。SSL
提供了证书,由值得信任的第三方机构颁发,用于证明服务器和客户端是实际存在的。客户端持有证书即可完成个人身份的确认,也可用于对Web
网站的认证环节。
HTTPS
并非是应用层的一种新协议,只是通信接口部分用SSL
和TLS
协议代替而已。通常HTTP
直接和TCP
通信,但当使用SSL
时,则演变为先和SSL
通信,再由SSL
和TCP
通信。SSL
是独立于HTTP
的协议,所以除了HTTP
外,其他应用层协议如SMTP
等也可以配合SSL
使用。
SSL
使用一种叫做公开密钥加密 ( $Public-key\ \ cryptography$ ) 的加密处理方式,使用私钥和公钥进行解密和加密。但是公开密钥加密方式还是存在问题,即无法证明公钥本身是公钥。为了解决这个问题,可以使用由数字证书认证机构 ( $CA$ ,$Certificate\ \ Authority$ ) 和其相关机关办法的公钥证书。
证书还可用于确认服务器背后运营的企业是否存在,即EV SSL
证书 ( $Extended\ \ Validation\ \ SSL\ \ Certificate$ )。除此之外,HTTPS
中还可以使用客户端证书进行客户端验证,但是存在着获取和发布的问题。
2.1 通信步骤
- 客户端发送 $Client\ \ Hello$ 报文开始
SSL
通信,报文包含SSL
版本、随机字符串 $client\ \ random$ 和加密组件列表; - 服务器以 $Server\ \ Hello$ 报文响应,同样包含
SSL
版本、随机字符串 $server\ \ random$ 和加密组件,服务器的加密组件是从客户端的加密组件中筛选的; - 服务器发送 $Certificate$ 报文,包含公钥证书;
- 服务器发送 $Server\ \ Hello\ \ Done$ 报文通知客户端,表示最初阶段的
SSL
握手协商部分结束; - 第一次
SSL
握手结束后,客户端以 $Client\ \ Key\ \ Exchange$ 报文回应,包含通信加密中使用的一种称为 $Pre-master\ \ secret$ 的随机密码串,使用公钥加密传输; - 客户端继续发送 $Change\ \ Cipher\ \ Spec$ 报文,提示服务器之后使用 $client\ \ random$ 、$server\ \ random$ 和 $Pre-master\ \ secret$ 密钥加密;
- 客户端发送 $Finished$ 报文,包含连接至今全部报文的整体校验值;
- 服务器发送 $Change\ \ Cipher\ \ Spec$ 报文;
- 服务器发送 $Finished$ 报文;
- 在 $Finished$ 报文交换完毕后,
SSL
连接建立完成,从此开始发送HTTP
请求; - 发送
HTTP
请求和响应; - 客户端断开连接,发送 $close_-notify$ 报文;
- 发送 $TCP\ \ FIN$ 关闭
TCP
通信。
以上流程中,应用层发送数据时会附加一种叫做MAC
( $Message\ \ Authentication\ \ Code$ ) 的报文摘要,能够查知报文是否被篡改。
和使用HTTP
相比,使用SSL
会使网络负载增加 $2$ 到 $100$ 倍,而且加密和解密也会带来额外的处理。
3. 发展
3.1 HTTP1.0
/HTTP1.1
HTTP1.0
最早在网页中使用是在 $1996$ 年,那个时候只是使用在一些较为简单的网页和网络请求上,而HTTP1.1
在 $1999$ 年才开始广泛应用于现在的各大浏览器网络请求中,也是当前使用最为广泛的HTTP
协议。主要区别体现在:
- 连接:
HTTP1.0
每次发送请求都要进行一次TCP
连接;HTTP1.1
新增 $Connection$ 字段,通过设置 $keep-alive$ 保持HTTP
连接不断,如果客户端想要关闭连接,可以通过设置 $Connection:false$ 进行关闭; - 传输:
HTTP1.0
规定下一个请求必须在前一个请求响应到达之前才能发送;HTTP1.1
引入了管道 ( $pipelining$ ),将多个请求整批提交,并且在发送过程中不需要先等待服务器响应。虽然可以一次性发出所有请求,但是在服务端接收到请求时还是一一处理,如果服务端返回的其中一个响应阻塞,接下来的响应也会被阻塞; - 缓存处理:
HTTP1.0
主要使用 $header$ 里的 $If-Modified-Since$ 和 $Expires$ 来作为缓存判断的标志;HTTP1.1
则引入了更多的缓存控制策略如 $If-Unmodified-Since$ 和 $If-Match$ 等; - 带宽优化及网络连接的使用:
HTTP1.0
中不支持分段传输,一次只能传输整个对象;HTTP1.1
引入了 $range$ 头,允许只请求资源的某个部分,返回码为 $206$ ; - 错误通知的管理:
HTTP1.1
新增了 $24$ 个错误状态响应码,如 $409$ 和 $410$ 等; Host
头处理:HTTP1.0
为每台服务器绑定一个唯一的IP
地址,因此请求中没有传递 $hostname$ 。但是随着技术发展,一台服务器上可以存在多个虚拟主机,共享IP
。HTTP1.1
支持 $Host$ 头,并且请求中如果没有 $Host$ 头会返回 $400$ 。
3.2 SPDY
/HTTP2.0
SPDY
是Google
在 $2012$ 年提出的,是一个综合了HTTP
和HTTPS
协议优点的传输协议。
- 降低延迟:
SPDY
使用了多路复用,多个请求共享同一个TCP
连接; - 请求优先级:多路复用可能会导致关键请求被阻塞,
SPDY
允许给请求设置优先级; - 消息头压缩:
HTTP1.x
的消息头很多时候都是重复多余的,通过合适的压缩算法可以减小包大小和数量; - 基于
HTTPS
的传输:保留HTTPS
的加密特性; - 服务端推送:采用了
SPDY
的网页允许服务端将文件额外推送给客户端。
SPDY
位于HTTP
之下,SSL
之上,可以兼容老版本HTTP
协议,同时可以使用已有的SSL
协议。但是SPDY
并不是一个标准协议。
HTTP2.0
的特性大部分和SPDY
类似,主要有:
- 二进制分帧:
HTTP1.x
基于文本解析,文本的表现形式很多,要做到健壮性很难;HTTP2.0
在HTTP
和SSL
之间增加了一个二进制分帧层,将传输信息分为更小的消息和帧,并采用二进制格式编码; - 多路复用:允许通过单一的
HTTP
连接发起多重请求,即一个TCP
连接上可以有多个请求,即 $stream$ 。每个连接的请求可以随机的混杂在一起,HTTP2.0
引入的二进制分帧 ,通过帧对数据进行顺序标识,接收方在接收到数据后可以按照序列对数据进行合并; - 消息头压缩:
HTTP2.0
使用压缩算法减少需要传输的消息头大小,通讯双方各自缓存一份消息头字段表,避免重复数据的传输; - 服务端推送:客户端发送资源请求后,服务器推断客户端需要的其他资源并一同发送给客户端,客户端可以将额外资源放入缓存中。如果客户端已经存在缓存,那么推送就是浪费资源,而且推送提高的性能也不高,大概就几百毫秒,所以只推送
CSS
是一个比较好的选择; - 主动重置连接:在
HTTP1.x
中,一个连接同一时间只能发送一个请求,如果需要中止,直接关闭即可;在HTTP2.0
中,多个 $stream$ 共享一个连接,如果关闭连接会影响其他 $stream$ ,$RST_-STREAM$ 允许立刻中止一个 $stream$ 。
HTTP2.0
可以说是SPDY
的升级版,与SPDY
的不同之处在于:
HTTP2.0
的消息头压缩算法使用HPACK
,而SPDY
使用DEFLATE
;HTTP2.0
初期支持HTTP
,而SPDY
强制使用HTTPS
,后期二者都使用HTTPS
。
3.3 HTTP3.0
HTTP3.0
也称作 $HTTP\ \ over\ \ QUIC$ ,由Google
在 $2015$ 年提出的SPDY v3
演化而来的新协议。传统的HTTP
协议基于TCP
,HTTP3.0
则基于UDP
,并且在UDP
的基础上加了一层,即QUIC
协议,保证可靠传输,实现了数据重传、拥塞控制等功能。
HTTP3.0
针对HTTP2.0
解决了以下问题:
- 减少了
TCP
和TLS
握手时间:HTTP3.0
基于UDP
,不需要握手。QUIC
也需要建立连接,但是在第一个数据包就可以传输数据; - 多路复用丢包时的队头阻塞问题:队头阻塞 ( $Head-of-line\ \ blocking$ ) 指一个数据包阻塞了后续数据包的现象。
HTTP2.0
的多路复用解决了HTTP
层的队头阻塞,但是没有解决TCP
层的队头阻塞。QUIC
基于UDP
实现,解决了队头阻塞的问题; - 前向纠错:前向纠错 ( $Forward\ \ Error\ \ Correction$, $FEC$ ) 是增加数据通讯可信度的方法,在单向通讯信道中,一旦错误被发现,其接收器将无权再次请求传输。
QUIC
每发送一组数据就对这组数据进行异或计算,并将结果作为一个FEC
包发送出去,接收方通过FEC
包即可进行校验和纠错; - 流量控制:在多路复用中允许同时存在多个请求 ( $stream$ ),如果有一个请求速度很慢,导致长时间占用缓存,
HTTP3.0
限制了单一 $stream$ 的缓存大小; - 连接迁移:
TCP
连接基于源IP
、源端口、目的IP
、目的端口的四元组,当连接发生变化时需要重新建立。HTTP3.0
不受四元组影响,当连接发生变化时可以维持该连接,不使用四元组标识,而是使用一个 $64$ 位的随机数,称为 $Connection\ \ ID$ ,对应每个 $stream$ 。
HTTP3.0
建立连接的可以分为首次和非首次两种情况,使用的交换算法是DH
( $Diffie-Hellman$ ) 算法。DH
算法的基本过程:
- 客户端发送 $client\ \ hello$ 请求;
- 服务端生成一个素数 $p$ 和一个整数 $g$ ,以及一个随机数 $K_{s_-pri}$ 作为私钥,然后计算出公钥 $K_{s_-pub} = g^{K_{s_-pri}}\ \ mod\ \ p$ ,服务端将 $K_{s_-pub}$ 、$p$ 和 $g$ 打包称为 $config$ ,发送给客户端;
- 客户端随机生成私钥 $K_{c_-pri}$ ,再从 $config$ 中读取 $p$ 和 $g$ ,计算公钥 $K_{c_-pub} = g^{K_{c_-pri}}\ \ mod\ \ p$ ;
- 客户端使用私钥 $K_{c_-pri}$ 和服务端发来的 $config$ ,读取服务端公钥 $K_{s_-pub}$ ,生成后续数据加密使用的密钥 $K=K_{s_-pub}^{K_{c_-pri}}\ \ mod\ \ p$ ;
- 客户端使用密钥 $K$ 加密,并将公钥 $K_{c_-pub}$ 传递给服务端;
- 服务端根据私钥 $K_{s_-pri}$ 和客户端公钥 $K_{c_-pub}$ 生成客户端密钥 $K = K_{c_-pub}^{K_{s_-pri}}\ \ mod\ \ p$ ;
- 密钥生成后只会使用一次,后续服务端会使用相同的规则生成公钥和密钥,并使用这组公钥生成新的密钥;
首次连接生成的 $config$ 会被客户端保存,并在后续连接中使用。$config$ 是有时限的,失效后仍然需要重新生成。
4. 认证
HTTP/1.1
使用的认证方式包括:BASIC
认证、DIGEST
认证、SSL
客户端认证和FormBase
认证。
4.1 BASIC
认证
- 服务器随状态码 $401\ \ Authorization\ \ Required$ 返回带 $WWW-Authenticate$ 首部字段的响应,字段包含认证方式 (
BASIC
) 和Request-URI
安全域字符串 ( $realm$ ); - 客户端将用户名
ID
及密码发送给服务器,中间以冒号连接,经过Base64
编码处理。 - 服务器对信息正确性进行验证。
4.2 DIGEST
认证
- 服务器随状态码 $401\ \ Authorization\ \ Required$ 返回带 $WWW-Authenticate$ 首部字段的响应,包含质问响应方式所需的临时质询码 ( 随机数,$nonce$ ) 和 $realm$ ;
- 客户端返回的响应首部字段 $Authorization$ 内包含 $username$ 、$realm$ 、$nonce$ 、$uri$ 和 $response$ 的字段信息;
- 服务器对信息正确性进行验证。
4.3 SSL
客户端认证
- 服务器发送 $Certificate\ \ Request$ 报文,要求客户端提供证书;
- 客户端将证书信息以 $Client\ \ Certificate$ 报文方式发送给服务器;
- 服务器验证客户端证书。
4.4 基于表单认证
- 客户端将用户
ID
和密码等信息放入报文的实体部分,通常通过 $POST$ 请求发送给服务器; - 服务器通过
Session ID
标识用户,并进行身份验证。通常会使用Cookie
传输Session ID
给客户端; - 客户端接收到
Session ID
后,将其作为Cookie
保存在本地。
5. CORS
CORS
全称 $Cross-Origin\ \ Resource\ \ Sharing$ ,即跨域资源共享,是一种让运行在一个域 ( $Origin$ ) 上的Web
应用被准许访问来自不同源服务器上指定资源的机制。Web
概念中域的内容由协议、主机和用于访问它的端口定义,当且仅当这三个内容都匹配时,两个对象才有相同域。协议相同、域名相同、端口相同的安全策略也被称为同源策略 ( $Same\ \ Origin\ \ Policy$ )。某些操作仅限于具有相同来源的内容,可以使用CORS
取消此限制。
出于安全的因素,浏览器限制了从脚本发起跨域的HTTP
请求。$XMLHttpRequest$ 和其他 $Fetch$ 接口会遵循同源策略。也就是说使用这些API
的应用程序想要请求相同的资源,那么他们应该具有相同的来源,除非来自其他来源的响应包括正确的CORS
标头。
跨域资源共享标准通过添加新的HTTP
标头来工作,这些标头允许服务器描述哪些来源的可以从Web
浏览器读取信息。另外,对于可能导致服务器产生副作用的HTTP
请求方法,该规范要求浏览器预检请求,即使用 $OPTIONS$ 请求从服务器请求受支持的方法。
6. Session
/Cookie
HTTP
是一种无状态协议,即每次服务端收到客户端的请求时,都是一个全新的请求,服务器并不知道客户端的历史请求记录。Session
和Cookie
的主要目的就是为了弥补HTTP
的无状态特性。
客户端请求服务端,服务端会为这次请求开辟一块内存空间,这个对象便是Session
对象,Java
语言中的结构通常为 $ConcurrentHashMap$ ,服务端可利用Session
存储客户端在同一个会话期间的一些操作记录。服务器在第一次接收到请求时,会生成一个 $SessionID$ ,并通过响应头的 $Set-Cookie:\ JSESSIONID=XXXXX$ 命令,向客户端发送要求设置的Cookie
响应。客户端接收到响应后,会设置 $JSESSIONID=XXXXX$ 的Cookie
信息,该Cookie
过期时间为浏览器会话结束时间。Session
机制有一个缺点,比如 $A$ 服务器存储了Session
,在做了负载均衡后,假设一段时间内 $A$ 的访问量激增,会转发到 $B$ 进行访问,但是 $B$ 并没有存储Session
。
Cookie
是服务器发送到Web
浏览器的一小块数据,浏览器会存储Cookie
,并与下一个请求一起发送到服务器。通常用于判断两个请求是否来自同一个浏览器,例如用户保持登录状态。Cookie
包括 $Session\ \ Cookie$ 和 $Persistent\ \ Cookie$ , 如果Cookie
不包含到期时间,则为会话Cookie
,否则为持久性Cookie
,在到期指定时间会从磁盘中删除。安全的Cookie
需要经过HTTPS
协议通过加密的方式发送到服务器,即使是安全的,也不应该将敏感信息存储在Cookie
中,因为它们本质上是不安全的。缺少 $HttpOnly$ 属性会导致攻击者可以通过程序获取到用户的Cookie
信息,造成用户Cookie
信息泄漏。
JWT
和Session
都可以为网站提供用户的身份认证。在Session Cookie
中,用户的登录状态会保存在服务器的内存中,当用户登录时,Session
就被服务端安全的创建。每次请求时,服务器都会从Cookie
中读取 $SessionID$ ,如果服务端数据和读取的 $SessionID$ 相同,那么服务器就会发送响应给浏览器,允许登录。JWT
中存储的信息是经过数字签名的,可以使用HMAC
算法或者使用RSA/ECDSA
的公用/专用密钥对JWT
进行签名。
JWT
是无状态的,因为声明被存储在客户端中,而不是服务端中,身份验证可以在本地进行,而不是在请求必须通过服务器数据库或类似位置中进行。这意味着可以对用户进行多次身份验证,而无需与站点或应用程序的数据库进行通信。由于Session Cookie
存储在服务器内存中,会耗费大量资源,而JWT
是无状态的,可以节省服务器资源。Session Cookie
只能用在单节点域或者它的子域中,如果尝试通过第三个节点访问,就会被禁止,而JWT
可以通过多个节点进行用户认证,也就是跨域认证。综上,对于一些中小型网站,如果只需要登录用户访问存储在站点数据库的一些信息,Session Cookie
就可以满足需求;对于企业级站点,需要处理大量请求,尤其是大量第三方域的访问,JWT
更合适。
7. WebSocket
WebSocket
是Web
浏览器与Web
服务器之间的全双工通信标准。一旦Web
服务器与客户端之间建立起WebSocket
协议的通信连接,之后所有的通信都依靠这个专用协议进行,并且可以互相发送任意格式的数据。由于是建立在HTTP
基础上的协议,因此连接的发起方仍是客户端,而一旦建立WebSocket
通信连接,不论服务器还是客户端,任意一方都可以直接向对方发送报文。
为了实现WebSocket
通信,需要用到HTTP
的 $Upgrade$ 首部字段。
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
$Sec-WebSocket-Key$ 字段内记录着握手过程中必不可少的键值。$Sec-WebSocket-Protocol$ 字段内记录使用的子协议,在连接分开使用时,定义连接的名称。
对于升级请求,返回 $101\ \ Switching\ \ Protocols$ 响应。
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
$Sec-WebSocket-Accept$ 字段值是由握手请求中的 $Sec-WebSocket-Key$ 的字段值生成的。在成功握手确立WebSocket
连接后,通信时不再使用HTTP
的数据帧,而是使用WebSocket
独立的数据帧。