社区微信群开通啦,扫一扫抢先加入社区官方微信群
社区微信群
参考资料:《图解HTTP》、《HTTP权威指南》
HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。HTTP是一个基于TCP/IP通信协议来传递数据
HTTP 协议用于客户端和服务器端之间的通信。HTTP 协议和 TCP/IP 协议簇内的其他众多的协议相同,用于客户和服务器之间的通信,请求访问文本或图像等资源的一端称为客户端,为提供资源响应的一端称为服务器端
起始行开头的 GET 表示请求访问服务器的类型,称为方法(method)。随后的字符串 /python-web-crawler/ 指明了请求访问的资源对象,也叫做请求 URI 。最后的 HTTP/1.1 ,即 HTTP 的版本号,用来提示客户端使用的 HTTP 协议功能。综合来看,这段请求的意思是:请求访问某台服务器上的 /python-web-crawler/ 对应的资源
请求报文是由请求方法、请求 URI 、协议版本、可选的请求首部字段和内容实体构成的
在起始行开头的 HTTP/1.1 表示服务器对应的 HTTP 版本号。接着的 200 OK 表示请求的处理结果状态码(status code)和原因短语(reason-phrase)。
响应报文基本上是由协议版本、状态码、用以解释状态码的原因短语、可选的响应首部字段以及实体主体构成
用于 HTTP 协议交互的信息称为 HTTP 报文。请求端(客户端)的 HTTP 报文叫做请求报文,响应端(服务器端)的 HTTP 报文叫做响应报文。
HTTP 报文的结构如下:
请求报文和响应报文的结构如下:
请求报文实例:
响应报文实例:
请求报文和响应报文的首部由以下数据组成:
请求报文中起始行的第一个字段表示请求访问服务器的类型,称为方法(method)
HTTP 状态码负责表示客户端 HTTP 请求的返回结果,标记服务器端的处理是否正常、通知出现的错误等工作。
状态码如 200 OK ,以 3 位数字和原因短语组成。
数字的第一位指定了响应的类别,后两位无分类。只要遵守了状态码类别的定义,及时改变 RFC 2616 中定义的状态码或服务器端自行改变自行创建状态码都没问题。
响应码的类别有以下 5 种:
类别 | 原因短语 |
---|---|
1XX | Infomational(信息性状态码) |
2XX | Success(成功状态码) |
3XX | Redirection(重定向状态码) |
4XX | Client Error(客户端错误状态码) |
5XX | Service Error(服务器端错误状态码) |
2XX 的响应结果表明请求被正常处理
3XX 响应结果表明浏览器需要执行某些特殊的处理以正确处理请求
4XX 的响应结果表明客户端发生了错误
5XX 的响应结果表明服务器本身发送错误
HTTP 首部字段是构成 HTTP 报文的要素之一。在客户端与服务器之间的以 HTTP 协议进行通信的过程中,无论是请求还是响应都会使用首部字段,它能起到额外重要信息的作用
HTTP 首部字段是由首部字段名和字段值构成的,中间用冒号“:”分隔
首部字段:字段值
例如,在 HTTP 首部中以 Content-Type 这个字段来表示报文主体的对象类型
Content-Type: text/html
另外,字段值对应单个 HTTP 首部字段可以由多个值,如下所示
Keep-Alive : timeout=15,max=100
HTTP 首部字段根据实际用途被分为以下 4 种类型
HTTP 首部字段按照定义缓存代理和非缓存代理的行为,分为 2 中类型
HTTP/1.1 规范中定义的通用首部字段
首部字段名 | 说明 |
---|---|
Cache-Control | 控制缓存的行为 |
Connection | 逐条首部、连接的管理 |
Date | 创建报文的日期时间 |
Pragma | 报文指令 |
Trailer | 报文末端的首部一览 |
Transfer-Encoding | 指定报文主体的传输编码方式 |
Upgrade | 升级为其他协议 |
Via | 代理服务器的相关信息 |
Warning | 错误通知 |
HTTP/1.1 规范中定义的请求首部字段
首部字段 | 说明 |
---|---|
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-Unmodifed-Since | 比较资源的更新时间(与If-Modified-Since相反) |
Max-Forwards | 最大传输逐跳数 |
Proxy-Authorization | 代理服务器要求客户端的认证信息 |
Range | 实体的字节请求范围 |
Referer | 对请求中 URI 的原始获取方 |
TE | 传输编码的优先级 |
User-Agent | HTTP 客户端程序的信息 |
HTTP/1.1 规范中定义的响应首部字段
响应首部字段 | 说明 |
---|---|
Accept-Range | 是否接收字节范围请求 |
Age | 推算资源创建经过时间 |
ETag | 资源的匹配信息 |
Location | 令客户端重定向到指定的 URI |
Proxy-Authenticate | 代理服务器对客户端的认证消息 |
Retry-After | 对再次发起请求的时机要求 |
Server | HTTP 服务器的安装信息 |
Vary | 代理服务器缓存的管理信息 |
WWW-Authenticate | 服务器对客户端认证信息 |
HTTP/1.1 规范中定义的实体首部字段
首部字段 | 说明 |
---|---|
Allow | 资源可支持的 HTTP |
Content-Encoding | 实体主体适用的编码方式 |
Content-Language | 实体主体的自然语言 |
Content-Length | 实体主体的大小(单位:字节) |
Content-Location | 替代对应资源的URI |
Content-MD5 | 实体主体的报文摘要 |
Content-Range | 实体主体的位置范围 |
Content-Type | 实体主体的媒体类型 |
Expires | 实体主体过期的日期时间 |
Last_Modified | 资源的最后修改时间 |
在 HTTP 协议通信交互中适用到的首部字段,不限于 RFC 2616 中定义的 47 种首部字段。还有 Cookie、Set-Cookie 和 Content-Disposition 等在其他 RFC 中定义的首部字段,它们的适用频率也很高
HTTP 是无状态协议,它不对之前发生过的请求和响应的状态进行管理,也就是说,无法根据之前的状态进行本次的请求处理。这样的优点是:由于不必保存状态,可减少服务器的 CPU 及内存的消耗,同时这也使得 HTTP 本身非常的简单。
但是,HTTP 的无状态也使得无法实现状态的管理,如登陆认证。为了解决这个问题于是引入了 Cookie 技术。
Cookie 技术通过在请求和响应报文中写入 Cookie 信息来控制客户端的状态。Cookie 会根据从服务区端发送的响应报文内一个叫做 Set-Cookie 的首部字段信息,通知客户端保存 Cookie。当下一次客户端再往服务器端发送请求的时候,客户端会自动在请求报文中自动加入 Cookie 值后发送出去。服务器端发现客户端发送过来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息
HTTP 协议的早期版本中,每进行一次 HTTP 通信就要断开一次 TCP 连接。
由于早期的互联网通信都是一些容量较少的文本传输,所以即使这样也没有多大问题。但是随着 HTTP 的普及,文档中包含大量的图片和其他资源,就需要进行多个请求,因此每次的请求都会造成无谓的 TCP 连接建立和断开,增加通信量的开销
为了解决上述 TCP 连接问题,HTTP/1.1 和一部分的 HTTP/1.0 提出了持久连接(HTTP Persistent Connections,也称为 HTTP Keep-Alive 或 HTTP connection reuse)的方法。持久连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态
持久化连接使得多数请求以管线化(Pipelining)方式发送成为可能,从前发送请求后需等待并收到响应,才能发送下一个请求。管线化技术出现后,加之 TCP 的持久连接,不用等待响应亦可直接发送下一个请求,这样就可以做到同时发送多个请求,而不需要一个接一个地等待响应了
HTTP 在传输数据时可以按照数据原貌直接传输,但也可以在传输过程中通过编码提升传输速率。通过在传输编码,能有效地处理大量的访问请求,但是将会消耗更多的 CPU 资源
HTTP 协议中的内容编码可以对报文实体的容量进行压缩,内容编码指明了应用在实体内容上的编码格式,并保持实体信息原样压缩。内容编码后的实体有客户端接收并负责解码
常用的内容编码有以下几种
在 HTTP 通信过程中,在传输大容量数据时,把数据分隔成多块让浏览器逐步显示页面,这种功能称为分块传输编码(Chunked Transfer Coding)。
分块传输编码会将实体主体分成多个部分(块)。每一块都会用十六进制来标记块的大小,而实体主体的最后一块会使用“0(CR + LF)”来标记。使用分块标记传输编码的实体主体会有接收的客户端负责解码,恢复到编码前的实体主体
内容协商机制是指客户端和服务器端就响应的资源内容进行交涉,然后提供给客户端最合适的资源。内容协商会以响应资源的语言、字符集、编码方式等作为判断标准
包含在请求报文中某些首部字段就是判断的基准,如下:
HTTP 具有相当优秀和方便的一面,然而也由不足之处,HTTP 的主要不足如下:
如果在 HTTP 协议通信中使用未经加密的明文,如果通信线路被窃听,那么通信的内容将会被泄露。另外,对于 HTTP 来说,服务器也好,客户端也好,都是无法确定对方,很由可能并不是与预想的通信方在时机通信,并且还需要考虑接收到的报文在通信途中已经遭到纂改的可能性。
为了解决以上问题,需要在 HTTP 上加入加密处理和认证机制。我们把加入加密及认证机制的 HTTP 称为 HTTPS
HTTP + 加密 + 认证 + 完整性保护 = HTTPS
HTTPS 并非是应用层的一种新协议,而是 HTTP 通信接口部分使用 SSL (Security Socket Layer) 和 TLS (Transfer Layer Security)协议代替。通常,HTTP 直接与 TCP 通信。当使用 SSL 时,则演变成先和 SSL 通信,在由 SSL 与 TCP 通信。简而言之,所谓的 HTTPS ,其实就是身披 SSL 协议的 HTTP 协议,并且 SSL 是独立于 HTTP 协议的
在采用 SSL 后,HTTP 就拥有了加密、证书和完整性保护的功能。
近代的加密方法是加密算法是公开的,为密钥确实保密的。通过这种方式得以保持加密方法的安全性。加密和解密都要用到密钥,没有密钥就无法对密码解密,相反,任何人持有了密钥就可以解密。如果密钥被攻击者获得,加密也就失去了意义
加密和解密使用同一个密钥的方式称为共享密钥加密(Common Key Crypto System),也称为对称密钥加密。
以共享密钥的方式加密时必须将密钥也发给对方,但是在怎样才能安全地转交密钥是一个问题,在互联网中转发密钥时,如果通信被监听,那么密钥就可能落入攻击者手中,失去了加密的意义,同时,使用者也需要想方设法的保管接收到的密钥
公开密钥加密方式可以很好地解决共享密钥加密的缺点。公开密钥加密使用一对非对称的密钥。一把叫做私有密钥(Private Key),另一把叫做公开密钥(Public Key)。顾名思义,私有密钥不能让其他人知道,而公开密钥则可以随意发布,任何人都可以获得。
使用公开密钥加密方式,发送密文的一方使用对方的公开密钥进行加密处理,对方收到被加密的信息后,再使用自己的私有密钥进行解密。利用这种方式,不需要发送用来解密的私有密钥,不必担心密钥被窃听而盗走。另外,要想根据密文和公开密钥,恢复到信息原文是异常困难的。
HTTPS 采用共享密钥加密和公开密钥加密两者并用的混合加密机制。因为公开密钥加密方式处理起来比共享密钥加密方式更为复杂,因此若在通信时使用公开密钥加密方式,效率就会很低。所以应该充分利用两者的优势,将多种方法组合起来用于通信,在交换密钥环节使用公开密钥加密方式,之后建立通信交换报文阶段则使用共享密钥加密方式
上面提到,使用公开密钥加密方式可以实现加密交换通信报文加密使用的密钥,但是仍然存在一些困难,就是如何证明收到的公开密钥就是原本预想的那一台服务器发行的公开密钥。或许在公开密钥传输过程中,真正的公开密钥已经被替换掉了
为了解决上述的问题,可以使用由数字证书认证机构(CA,Certificate Authority)和其他相关机关颁发的公开密钥证书,公钥证书也可以叫做数字证书或者证书。数字证书认证机构处于客户端与服务器双方都可信赖的第三方机构的立场上。
服务器会将这份由数字证书认证机构颁发的公钥证书发送给客户端,以进行公开密钥加密方式通信。接收到证书的客户端可使用数字证书认证机构的公开密钥,对那张证书上的数字签名进行验证,一旦验证通过,客户端便可确认两件事:一、认证服务器的公开密钥是真实有效的数字证书认证机构。二、服务器的公开密钥是值得信赖的
需要注意的是,数字证书认证机构是实现对服务器发送的数字证书进行认证的关键,必须保证是在正确可信赖的认证机构进行证书的认证,防止攻击者伪造,这需要认证机关的公开密钥安全的转交到客户端,但是如可安全转交是很困难的事,故多数浏览器发布时都会事先在内部植入常用的认证机关的公开密钥
HTTPS 的通信步骤如下:
HTTP/1.1 使用的认证方式如下所示:
BASIC 认证是从 HTTP/1.1 就定义的认证方式。其认证步骤如下:
BASIC认证的缺点:
BASIC 认证使用上的不够便捷灵活,且达不到多数 Web 网站的安全性等级,因此并不常用
为了弥补 BASIC 认证存在的弱点,从 HTTP/1.1 起就有了 DIGEST 认证。DIGEST 同样使用了质询/响应的方式,但不会像 BASIC 认证那样直接发送明文密码
所谓的质询响应方式是指,一开始一方会发送认证要求给另一方,接着使用另一方那里接收到的质询码计算生成响应码,最后将响应码返回给对方的认证方式。
DIGEST 认证步骤
请求需认证的资源时,服务器会随状态码 401 Authorization Required,返回带 WWW-Authorizate 首部字段的响应,该字段内包含质询响应方式认证所需的临时质询码(随机数,nonce)
首部字段 WWW-Authorizate 中必须包含 realm 和nonce 这两个字段的信息。客户端就是依靠向服务器回送的这两个值进行认证的
接收到 401 状态码的客户端,返回的响应中包含 DIGEST 认证必须的首部字段 Authorization 信息
首部字段 Authorization 内必须包含 username、realm、nonce、uri 和 response 的字段信息。其中,realm 和 nonce 就是从服务器接收到的响应中的字段。username 就是 realm 限定范围内可进行认证的用户名。uri 即 Request-URI 的值,但考虑到经代理转发后 Request-URI 的值可能被修改,因此会事先复制一份副本保存在 uri 内。response 也可以叫做 Request-Digest ,存放经过 MD5 运算后的密码字符串,形成响应码
接收到包含首部字段 Authorizaton 请求的服务器,会确认认证信息的正确性,认证通过后则返回包含 Request-URI 资源的响应。并且在此时会在首部字段 Authorization-Info 写入一些认证成功的相关信息
DIGEST 认证的缺点:
DIGEST 认证和 BASIC 认证一样,使用上不那么便捷灵活,且仍旧达不到多数 Web 网站对高度安全等级的要求
SSL 客户端认证时借由 HTTPS 客户端证书完成的方式,凭借客户端证书认证,服务器可确认访问是否来自已登陆的客户端
SSL 客户端认证的认证步骤:
为达到 SSL 客户端认证的目的,需要事先将客户端证书发送给客户端,且客户端必须安装此证书
SSL 认证方式的缺点:
基于表单的认证方式并不是 HTTP 协议中定义的。客户端会向服务器上的 Web 程序发送登陆信息,按登陆信息的验证结果认证
根据 Web程序的时机安装,提供的用户界面及认证方式也各不相同。
由于使用上的便利性及安全性问题,HTTP 协议标准提供的 BASIC 认证和 DIGEST 认证几乎不怎么使用。另外,SSL 客户端认证虽然具有高度的安全等级,但因导入及维护费用问题,还尚未普及,故当前多半使用的是基于表单的认证
随着时代的发展,Web 的用途多样化,网站追求的功能越来越多,这些网站所追求的功能可通过 Web 应用和脚本程序实现,即使这些功能已经满足需求,在性能上未必是最优的,这是由于 HTTP 协议上的限制以及自身性能有限,以下这些 HTTP 标准就会成为瓶颈
Google 在2010 年发布了 SPDY ,其开发目标旨在解决 HTTP 的性能瓶颈,缩短 Web 页面的加载时间。期间,陆续出现的 Ajax 和 Comet 等提高易用性的技术,一定程度上使 HTTP 得到改善,但 HTTP 协议本身限制令人束手无策,SPDY 为了在协议级别消除 HTTP 所遭遇的瓶颈,SPDY 并没有完全改写 HTTP 协议,而是在 TCP/IP 的应用层与运输层之间添加新会话层的形式运作
使用 SPDY 后,HTTP 协议获得额外以下功能:
WebSocket,即 Web 浏览器与 Web 服务器之间全双工通信标准,是 HTML5 标准的一部分,WebSocket API 由 W3C 定为标准。
一旦 Web 服务器与客户端之间建立起 WebSocket 协议的通信连接,之后所有的通信都依靠于这个专用的协议进行。通常过程中可项目发送 JSON 、XML、HTML 或图片等任意格式的数据
由于建立在 HTTP 基础上的协商,因此连接的发起方仍然是客户端,而一旦确认 WebSocket 通信连接,不论服务器还是客户端,任意一方都可直接向对方发送报文
WebSocket 协议的主要特点:
为了实现 WebSocket 通信,在 HTTP 连接建立之后,需要完成一次“握手步骤”
为了实现 WebSocket 通信,需要使用到 HTTP 的 Upgrade 首部字段,告知服务器通信协议发生改变,已达到握手的目的
Sec-WebSocket-Key 字段内记录者握手过程中必不可少的键值。Sec-WebSocket -Protocol 字段记录使用的子协议
对于之前的请求,返回状态码 101 Switching Protocol 的响应
Sec-WebSocket-Accept 的字段值是由握手请求中的 Sec-WebSocket-Key 的字段生成。成功握手确立 WebSocket 连接之后,通信是不再使用 HTTP 的数据组,而是使用 WebSocket 独立的数据帧
WebSocket 连接的建立过程如下:
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!