HTTP协议
基础概念
URI、URL和URN
URI包含URL和URN
- URI统一资源标识符
- URL统一资源定位符
- URN统一资源名称
请求和响应报文
-
请求报文
-
请求信息头
- 请求行
- 请求头
-
空白行隔开请求头和请求体
-
请求信息体
-
-
响应报文
-
响应信息头
- 状态行
- 响应头
-
空白行隔开响应头和响应体
-
响应信息体
-
HTTP方法
客户端发送的请求报文第一行为请求行,包含了方法字段
GET
- 获取资源,当前网络请求中,绝大部分使用的是GET方法
HEAD
- 获取报文首部,和GET方法一样,但不返回报文实体主体部分,主要用于确认URL的有效性以及资源更新的日期时间等
POST
- 传输实体主体。POST主要用来传输数据,而GET主要用来获取资源
PUT
- 上传文件。由于自身不带验证机制,任何人都可以上传文件,存在安全性问题,一般不使用该方法
PATCH
- 对资源进行部分修改。PUT也可以用于修改资源,但是只能完全替代原始资源,PATCH允许部分修改
DELETE
- 删除文件。与PUT功能相反,并且同样不带验证机制
OPTIONS
- 查询支持的方法。查询指定的URL能够支持的方法,会返回Allow:GET,POST,HEAD.OPTIONS这样的内容
CONNECT
- 要求在与代理服务器通信时建立隧道,使用SSL安全套接层和TLS传输层安全协议把通信内容加密后经网络隧道传输
TRACE
- 追踪路径。服务器会将通信路径返回客户端,发送请求时在Max-Forwards首部字段中填入数值,每经过一个服务器就会减1,当数值为0时就停止传输,通常不会使用TRACE,容易收到XST攻击即跨站追踪
HTTP状态码
服务器返回的响应报文中第一行为状态行,包含状态码以及原因短语用来告知客户端请求的结果
1XX 信息
- 信息性状态码,表示接收的请求正在处理
- 表示到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应
2XX 成功
-
成功状态码,表示请求正常处理完毕
-
200
- 表示OK
-
204 No Content
- 表示请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息而不需要返回数据时使用
-
206 Partial Content
- 表示客户端进行了范围请求,响应报文包含由Content-Range指定范围的实体内容
3XX 重定向
-
重定向状态码,表示需要进行附加操作以完成请求
-
301 Moved Permanently
- 表示永久性重定向
-
302 Found
- 表示临时性重定向
-
303 See Other
- 和302有着相同的功能,但是303明确要求客户端应该采用GET方法获取资源
-
304 Not Modified
- 如果请求报文首部包含一些条件例如if-Match、if-Range等如果不满足条件,则服务器会返回304状态码
-
307 Temporay Redirect
- 临时重定向,与302的含义相似,但是307要求浏览器不会把重定向请求的POST方法改成GET方法
4XX 客户端错误
-
客户端错误状态码,表示服务器无法处理请求
-
400 Bad Request
- 表示报文中存在语法错误
-
401 Unauthorized
- 表示发送的请求需要由认证信息如BASIC认证、DIGEST认证等,如果之前已进行过一次请求,则表示用户认证失败
-
403 Forbidden
- 表示请求被拒绝
-
404 Not Found
- 表示页面找不到
5XX 服务器错误
-
服务器错误状态码,表示服务器处理请求出错
-
500 Internal Server Error
- 表示服务器正在执行请求时发生错误
-
503 Service Unavailable
- 表示服务器暂时处于超负载或正在进行停机维护,现在无法处理请求
HTTP首部
通用首部字段
- Cache-Control控制缓存的行为
- Connection控制不再转发给代理的首部字段,管理持久连接
- Date创建报文的日期时间
- Pragma报文指令
- Trailer报文末端的首部一览
- Transfer-Encoding指定报文主体的传输编码方式
- Upgrade升级为其他协议
- Via代理服务器的相关信息
- Warning错误通知
请求首部字段
- Accept用户代理可处理的媒体类型
- Accept-Charset优先的字符集
- Accept-Encoding优先的内容编码
- Accept-Language优先的语言(自然语言)
- AuthorizationWeb 认证信息
- 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对再次发起请求的时机要求
- ServerHTTP 服务器的安装信息
- Vary代理服务器缓存的管理信息
- WWW-Authenticate服务器对客户端的认证信息
实体首部手段
- Allow资源可支持的 HTTP 方法
- Content-Encoding实体主体适用的编码方式
- Content-Language实体主体的自然语言
- Content-Length实体主体的大小
- Content-Location替代对应资源的 URI
- Content-MD5实体主体的报文摘要
- Content-Range实体主体的位置范围
- Content-Type实体主体的媒体类型
- Expires实体主体过期的日期时间
- Last-Modified资源的最后修改日期时间
具体应用
Cookie
-
HTTP协议是无状态的,主要是为了让HTTP协议尽可能简单,使得它能够处理大量事务,HTTP/1.1引入cookie来保存状态信息
-
cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器之后向同一服务器再次发起请求时携带上,用于告知服务端两个请求是否来自同一浏览器,由于之后每次请求都会需要携带cookie数据,因此会带来额外的性能开销
-
用途
-
会话状态管理
- 如用户登录状态、购物车、游戏分数或其他需要记录的信息
-
个性化设置
- 如用户自定义设置、主题等
-
浏览器行为跟踪
- 如跟踪分析用户行为等
-
-
创建过程
- 服务器发送的响应报文包含Set-Cookie首部字段,客户端得到响应报文后把Cookie内容保存到浏览器中
- 客户端之后对同一个服务器发送请求时,会从浏览器中取出Cookie信息并通过Cookie请求首部字段发送给服务器
-
分类
-
会话期Cookie
- 浏览器关闭之后它会被自动删除,也就是仅在会话期内有效
-
持久性Cookie
- 指定应该特定的过期时间或有效期之后就成为了持久性的Cookie
-
-
JavaScript获取Cookie
- 通过Document.cookie属性可创建新的Cookie,也可通过该属性访问非HttpOnly标记的Cookie
-
Secure和HttpOnly
- 标记为Secure的Cookie只能通过被HTTPS协议加密过的请求发送给服务端,即使设置了Secure标记,敏感信息也不应该通过Cookie传输,因为Cookie其固有的不安全性,Secure标记也无法提供确实的安全保障
- 标记为HttpOnly的Cookie不能被JavaScript脚本调用。跨站脚本攻击常常使用JavaScript的Document.cookie API窃取用户的Cookie信息,因此使用HttpOnly标记可以在一定程度上避免XSS攻击
-
作用域
- Domain标识指定了哪些主机可以接收Cookie,如果不指定默认为当前文档的主机,如果指定了Domain则一般包含子域名,如果设置Domain=mozilla.org,则Cookie也包含在子域名中如developer.moilla.org
- Path标识指定了主机下的哪些路径可以接收Cookie(该URL路径必须存在请求URL中)例如设置Path=/docs,则以下地址都会匹配
/docs
/docs/Web
/docs/Web/HTTP
-
Session
-
除了可以将用户信息通过Cookie存储在用户浏览器中,也可以利用Seeion存储在服务器端,存储在服务端的信息更加安全
-
Session可以存储在服务器上的文件、数据库或者内存中,也可以将Seeion存储在Redis这种内存型数据库中,效率会更高
-
使用Session维护用户登录状态的过程
- 用户进行登录时,用户提交包含用户名和密码的表单,放入HTTP请求报文中
- 服务器验证该用户名和密码
- 如果正确则把用户信息存储在Redis中,它在Redis中的Key成为Session ID
- 服务器返回的响应报文的Set-Cookie首部字段包含了这个Session ID,客户端接收到响应报文之后将该Cookie值存入浏览器中
- 客户端之后对同一个服务器进行请求时会包含该Cookie值,服务器收到之后提取出Session ID,从Redis中取出用户信息,继续之前的业务操作
- Session ID存在安全问题,不能让恶意攻击者轻易获取,产生的Session ID不能容易被猜到,还需要经常重新生成Session ID。在对安全性要求极高的情景下,例如转账操作,除了使用Session管理用户状态之外,还需要对用户进行重新验证,比如重新输入密码,或者使用短信验证码等方式
-
-
浏览器禁用Cookie
- 如果无法使用cookie来保存用户信息,只能使用session,也就无法将Session ID 存放到Cookie中,而是使用URL重写技术,将Session ID作为URL的参数进行传递
-
Cookie与Session的选择
- Cookie只能存储ASCII码字符串,而Session可以存取任何类型的数据,因此在考虑数据复杂性时首选Session
- Cookie存储在浏览器中,容易被恶意查看,如果非要将一些隐私数据存在cookie中,可以将cookie值进行加密,然后在服务器进行解密
- 对于大型网站,如果用户所有的信息都存储在Session中,开销是非常大的,所以不建议所有的用户信息都存储到Session中
缓存
-
优点
- 缓解服务器压力
- 降低客户端获取资源的延迟,缓存通常位于内存中,读取缓存的速度更快,并且缓存在地理位置上也有可能比源服务器来得近,例如浏览器缓存
-
实现方式
- 让代理服务器进行缓存
- 让客户端浏览器进行缓存
-
Cache-Control
-
禁止进行缓存
- no-store指令规定不能对请求或响应的任何一部分进行缓存
Cache-Control:no-store
- no-store指令规定不能对请求或响应的任何一部分进行缓存
-
强制确认缓存
- no-cache指令规定服务器需要先向源服务器验证缓存资源的有效性,只有当缓存资源有效才使用该缓存对客户端的请求进行响应
Cache-Control:no-cache
- no-cache指令规定服务器需要先向源服务器验证缓存资源的有效性,只有当缓存资源有效才使用该缓存对客户端的请求进行响应
-
私有缓存和公共缓存
- private指令规定了将资源作为私有缓存,只能被单独用户所使用,一般存储在用户浏览器中
Cache-Control:private - public指令规定了将资源作为公共缓存,可以被多个用户所使用,一般存储在代理服务器中
Cache-Control:public
- private指令规定了将资源作为私有缓存,只能被单独用户所使用,一般存储在用户浏览器中
-
缓存过期机制
- max-age指令出现在请求报文中,并且缓存资源的缓存时间小于该指令指定的时间,那么就能接收该缓存
max-age指令出现在响应报文中,表示缓存资源在缓存服务器中保存的时间
Cache-Control:max-age=31536000
- max-age指令出现在请求报文中,并且缓存资源的缓存时间小于该指令指定的时间,那么就能接收该缓存
-
缓存验证
- 通过ETag首部字段这一资源的唯一标识,URL不能唯一表示资源,例如http://www.google.com/有中文和英文两个资源,只有ETag才能对这两个资源进行唯一标识
-
连接管理
-
短连接和长连接
-
当浏览器访问一个包含多张图片的HTML页面时,除了请求访问的HTML页面资源,还会请求图片资源,如果每进行一次HTTP通信就要新建一个TCP连接,那么开销就会很大
-
长连接只需要建立一次TCP连接就能进行多次HTTP通信
- 从HTTP/1.1开始默认是长连接,如果要断开连接,需要由客户端或者服务端提出断开,使用Connection:close;
- 在HTTP/1.1之前默认是短连接,如果需要使用长连接,则使用Connection:Keep-Alive
-
-
流水线
- 默认情况下,HTTP请求是按顺序发出的,下一个请求只有在当前请求收到响应之后才会被发出,由于会受到网络延迟和带宽的限制,在下一个请求被发送到服务器之前,可能需要等待很长时间
- 流水线是在同一条长连接上发出连续的请求,而不用等待响应返回,这样可以避免连接延迟
内容协商
-
通过内容协商返回最合适的内容,例如根据浏览器的默认语言选择返回中文界面还是英文界面
-
类型
-
服务端驱动型
-
客户端设置特定的HTTP首部字段,例如Accept、Accept-Charset、Accept-Encoding,Accept-Language、Content-Language,服务器根据这些字段返回特定的资源
-
存在以下问题
- 服务器很难知道客户端浏览器的全部信息
- 客户端提供的信息相当冗长,并且存在隐私风险
- 给定的资源需要返回不同的展现形式,共享缓存的效率会降低,而服务端的实现会越来越复杂
-
-
代理驱动型
- 服务器返回300 Multiple Choices或者406 Not Acceptable,客户端从中选出最合适的那个资源
-
-
Vary
- 在使用内容协商的情况下,只有当缓存服务器中的缓存满足内容协商时,才能使用该缓存,否则应该向源服务器请求该资源
- 例如客户端发送了一个包含Accept-language首部字段的请求之后,源服务器返回的响应包含Vary:Accept-language内容,缓存服务器对这个响应进行缓存之后,在客户端下一次访问同一个URL资源,并且Accept-language与缓存中的对应的值相同时才会返回该缓存
内容编码
- 内容编码将实体主体进行压缩,从而减少传输的数据量
- 常用的内容编码有:gzip、compress、deflate、indentity
- 浏览器发送Accept-Encoding首部,其中包含有它所支持的压缩算法,以及各自的优先级,服务器则从中选择一种,使用该算法对响应的消息主体进行压缩,并且发送Content-Encoding首部来告知浏览器它选择了哪一种算法,由于该内容协商是基于编码类型来选择资源的展现形式,在响应的Vary首部至少要包含Content-Encoding
范围请求
-
如果网络出现中断,服务器只发送了一部分数据,范围请求可以使得客户端只请求服务器未发送的那部分资源,从而避免服务器重新发送所有数据
-
Range
- 在请求报文中添加Range首部字段指定请求的范围
如Range:bytes=0-1023 - 请求成功的话服务器返回的响应包含
206 Partial Content状态码
- 在请求报文中添加Range首部字段指定请求的范围
-
Accept-Ranges
- 响应首部字段Accept-Ranges用于告知客户端是否能处理范围请求,可以处理使用bytes,否则用none
Accept-Ranges:bytes
- 响应首部字段Accept-Ranges用于告知客户端是否能处理范围请求,可以处理使用bytes,否则用none
-
响应状态码
- 在请求成功的情况下,服务器会返回206 Partial Content状态码
- 在请求的范围越界的情况下,服务器会返回416 Request Range Not Satisfiable状态码
- 在不支持范围请求的情况下,服务器会返回200 OK状态码
-
分块传输编码
- Chunked Transfer Coding,可以把数据分割成多块,让浏览器逐步显示页面
虚拟主机
- HTTP/1.1使用虚拟主机技术,使得一台服务器拥有多个域名,并且在逻辑上可以看成多个服务器
通信数据转发
-
代理
-
代理服务器接受客户端的请求,并且转发给其他服务器
-
使用代理的主要目的是
- 缓存
- 负载均衡
- 网络访问控制
- 访问日志记录
-
代理服务器分为正向代理和方向代理两种
- 用户察觉得到正向代理的存在
- 反向代理一般位于内部网络,用户察觉不到
-
-
网关
- 与代理服务器不同的是,网关服务器会将HTTP转化未其他协议进行通信,从而请求其他非HTTP服务器的服务
-
隧道
- 使用SSL等加密手段,在客户端和服务器之间建立一条安全的通信线路
HTTPs
HTTP有以下安全性问题
- 使用铭文进行通信,内容可能被窃听
- 不验证通信方的身份,通信方的身份有可能遭遇伪装
- 无法证明报文的完整性,报文有可能遭篡改
HTTPs并不是新协议,而是让HTTP先和SSL通信,再由SSL和TCP通信,也就是说HTTPs使用了隧道进行通信
通过使用SSL,HTTPs具有了加密(防窃听)、认证(防伪装)和完整性(防篡改)
加密
-
对称密钥加密
- 加密和解密使用同一密钥
- 优点:运算速度快
- 缺点:无法安全地将密钥传输给通信方
-
非对称加密
- 又称公开密钥加密,加密和解密使用不同的密钥
- 公开密钥所有人都可以获得,通信发送方获得接收方的公开密钥之后,就可以使用公开密钥进行加密,接收方收到通信内容后使用私有密钥解密
- 非对称密钥除了用来加密,还可以用来进行签名,因为私有密钥无法被其他人获取,因此通信发送方使用起私有密钥进行签名,通信接收方使用发送方的公开密钥对签名进行解密,就能判断这个签名是否正确
- 优点:可以更安全地将公开密钥传输给通信发送方
- 缺点:运行速度慢
-
HTTPs采用的加密方式
- HTTPs采用混合的加密机制,使用非对称密钥加密用于传输对称密钥来保证传输过程的安全性,之后使用对称密钥加密进行通信来保证通信工程的效率
认证
- 通过使用整数来对通信方进行认证
- 数字证书认证机构CA是客户端与服务器双方都可信赖的第三方机构
- 服务器的运营人员向CA提出公开密钥的申请,CA再判明提出申请者的身份之后,会对已申请的公开密钥做数字签名,然后分配这个已签名的公开密钥,并将该公开密钥放入公开密钥证书后绑定在一起
- 进行HTTPs通信时,服务器会把证书发送给客户端,客户端取得其中的公开密钥之后,先使用数字签名进行验证,如果验证通过就可以开始通信了
- 通信开始时,客户端需要使用服务器的公开密钥将自己的私有密钥传输给服务器,之后再进行对称密钥加密
完整性保护
- SSL提供报文摘要功能来进行完整性保护
- HTTP也提供了MD5报文摘要功能,但不是安全的,例如报文内容被篡改之后,同时重新计算MD5的值,通信接收方是无法意识到发送了篡改
- HTTPs的报文摘要功能之所以安全,是因为它结合了加密和认证两个操作,加密之后的报文,遭到篡改之后,也很难重新计算报文摘要, 因为无法轻易获取明文
HTTPs的缺点
- 因为需要进行加密解密等过程,因此速度会更慢
- 需要支付证书授权的高额费用
HTTP/2.0
HTTP/1.x缺陷
-
实现简单是以牺牲性能为代价的
- 客户端需要使用多个连接才能实现并发和缩短延迟
- 不会压缩请求和响应首部,从而导致不必要的网络流量
- 不支持有效的资源优先级,导致底层TCP连接的利用率低下
二进制分帧层
-
HTTP/2.0将报文分成headers帧和data帧,它们都是二进制格式的
-
在通信过程中,只会有一个TCP连接存在,它承载了任意数量的双向数据流
- 一个数据流都有一个唯一标识符和可选的优先级信息,用于承载双向信息
- 消息是与逻辑请求或响应信息对应的完整的一系列帧
- 帧是最小的通信单位,来自不同数据流的帧可以交错发送,然后再根据每个帧头的数据流标识符重新组装
服务端推送
- HTTP/2.0在客户端请求一个资源时,会把相关的资源一起发送给客户端,客户端就不需要再次发起请求了,例如客户端请求page.html页面,服务端就把script.js和style.css等与之相关的资源一起发给客户端
首部压缩
- HTTP/1.1的首部带有大量信息,而且每次都要重复发送
- HTTP/2.0要求客户端和服务器同时维护和更新一个包含之前见过的首部字段表,从而避免了重复传输
- HTTP/2.0也使用Huffman编码对首部字段进行压缩
Get和Post的比较
作用
- GET用于获取资源
- POST用于传输实体主体
参数
- GET和POST的请求都能使用额外的参数,但是GET的参数是以查询字符串出现在URL中,而POST的参数存储在实体主体中。
- 虽然POST参数存储在实体主体中,但并不意味着它的安全性更高,因为照样可以通过一些抓包工具查看
安全
- 安全的HTTP方法不会改变服务器状态,也就是说它只是可读的
- GET方法是安全的,而POST却不是,因为POST的目的是传送实体主体内容,这个内容可能是用户上传的表单数据,上传成功只会,服务器可能把这个数据存储到数据库中,因此状态也就发生了改变
- 安全的方法除了GET之外还有HEAD、OPTIONS
- 不安全的方法除了POST之外还有PUT、DELETE
幂等性
- 幂等的的HTTP方法,同样的请求被执行一次或连续执行多次的效果是一样的,服务器的状态也是一样的
- 所有的安全方法都是幂等的
- 在正确实现的条件下,GET、HEAD、PUT和DELETE等方法都是幂等的,而POST方法不是
可缓存
-
如果要对响应进行缓存,需要满足以下条件
- 请求报文的HTTP方法本身是可缓存的,包括GET和HEAD,但是PUT和DELETE不可缓存,POST在多数情况下不可缓存的
- 响应报文的状态码是可缓存的
- 响应报文的Cache-Control首部字段没有指定不进行缓存
XMLHttpRequest
-
xhr是一个API,它为客户端提供了在客户端和服务器之间传输数据的功能,它提供了一个通过url来获取数据的简单方式,并且不会使整个页面刷新。这使得网页只更新一部分页面而不会打扰到用户。xhr在Ajax中被大量使用
- 在使用xhr的post方法时,浏览器一般会先发送header再发送data
- GET方法header和data会一起发送