HTTP简介
HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。
HTTP位于应用层。它的请求是建立在一些底层协议的基础上完成的。如TCP/IP协议栈中,HTTP需要TCP的三次握手连接成功后才能向服务器发起请求。当然,如果是HTTPS的话,还需要TSL和SSL安全层。
HTTP.JPGHTTP协议工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。
HTTP的特点
-
支持客户/服务器模式。
-
简单快速:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST。每种方法规定了客户与服务器联系的类型不同。由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
-
灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type(Content-Type是HTTP包中用来表示内容类型的标识)加以标记。
-
无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
-
无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
HTTP的无连接
早期每个客户端(即浏览器)与服务器之间交换数据的间歇性较大,HTTP被设计为请求时建连接、请求完释放连接,以尽快将资源释放出来服务其他客户端。
随着时间的推移,网页变得越来越复杂,里面可能嵌入了很多图片,这时候每次访问图片都需要建立一次 TCP 连接就显得很低效。后来,Keep-Alive 被提出用来解决这效率低的问题。
Keep-Alive 功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive 功能避免了建立或者重新建立连接。
这样一来,客户端和服务器之间的 HTTP 连接就会被保持,不会断开(超过 Keep-Alive 规定的时间,意外断电等情况除外),当客户端发送另外一个请求时,就使用这条已经建立的连接。
HTTP的无状态
HTTP 是一个无状态协议,这意味着每个请求都是独立的,Keep-Alive 没能改变这个结果。
缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。
客户端与服务器进行动态交互的 Web 应用程序出现之后,HTTP 无状态的特性严重阻碍了这些应用程序的实现,毕竟交互是需要承前启后的。于是,两种用于保持 HTTP 连接状态的技术就应运而生了,一个是 Cookie,而另一个则是 Session。
Cookie
Cookie诞生的最初目的是为了存储web中的状态信息,以方便服务器端使用。最典型的应用是判定注册用户是否已经登录网站。
Cookie的处理流程为:
- 服务器向客户端发送cookie
- 浏览器将cookie保存
- 之后每次http请求浏览器都会将cookie发送给服务器端(当然,不排除用户手工删除Cookie。还有一些Cookie在用户退出会话的时候就被删除了,这样可以有效保护个人隐私)
Session
Cookie是记录在客户端的,而Session是记录在服务端的。
当客户端访问服务器否个网页的时候,会在服务器端的内存里开辟一块内存,这块内存就叫做session,而这个内存是跟浏览器窗口关联在一起的。就是当访问一个页面的时候服务器会给浏览器创建一个独一无二的号码,叫sessionID。这样就可以在打开同一个网站的第二个页面时获取到第一个页面中session保留下来的对应信息。
session的两种实现方式:
-
通过cookies实现:服务器创建session出来后,会把session的id号,以cookie的形式回写给客户机,这样,只要客户机的浏览器不关,再去访问服务器时,都会带着session的id号去,服务器发现客户机浏览器带session id过来了,就会使用内存中与之对应的session为之服务。若当浏览器禁用或不支持cookie的情况下,就可以通过第二种方式获取session内存中的数据资源。
-
通过URL重写来实现:当禁用cookie了,这就需要每次请求的时候,都需要把session id告诉服务端,所以可以对访问的url进行重写,将session id作为一个参数添加进去,同样能达到确认身份的目的。
Cookie和Session的区别
- 于Cookie是记录在客户端的,而Session是记录在服务端的。
- cookie在过期时间之前一直有效,即使窗口或浏览器关闭;客户端的sessionID在当前浏览器窗口关闭后自动删除,但服务器保存的 Session 数据不是立即释放,此时数据还会存在。当然我们可以设置一个 Session 超时时间,一旦超过规定时间没有客户端请求时,服务器就会清除对应 SessionId 的 Session 信息。
- Cookie对于浏览器的不同窗口是共享的。而Session对于浏览器的不同窗口不共享
- Cookie数据大小不能超过4k,Session虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
HTTP的各个版本
HTTP/0.9
HTTP协议的最初版本,功能简陋,仅支持请求方式GET,并且仅能请求访问HTML格式的资源。
HTTP/1.0
在0.9版本上做了进步,增加了请求方式POST和HEAD;
不再局限于0.9版本的HTML格式,根据Content-Type可以支持多种数据格式,即MIME多用途互联网邮件扩展,例如text/html、image/jpeg等;
同时也开始支持cache,就是当客户端在规定时间内访问统一网站,直接访问cache即可。
再次,HTTP请求和回应的格式也变了。除了数据部分,每次通信都必须包括头信息(HTTP header),用来描述一些元数据。
但是1.0版本的工作方式是:每次TCP连接只能发送一个请求,当服务器响应后就会关闭这次连接,下一个请求需要再次建立TCP连接。
为了解决TCP连接的新建成本很高的问题,有些浏览器在请求时,用了一个非标准的keep-alive Connection字段。这个字段要求服务器不要关闭TCP连接,以便其他请求复用。
HTTP/1.1
- 持久连接
1.1 版的最大变化,就是引入了持久连接(persistent connection),即TCP连接默认不关闭,一个TCP连接可以允许多个HTTP请求复用,不用声明Connection: keep-alive。客户端和服务器发现对方一段时间没有活动,就可以主动关闭连接。不过,规范的做法是,客户端在最后一个请求时,发送Connection: close,明确要求服务器关闭TCP连接。
- 管道机制
加入了管道机制,在同一个TCP连接里,允许多个请求同时发送,增加了并发性,进一步改善了HTTP协议的效率。举例来说,客户端需要请求两个资源。以前的做法是,在同一个TCP连接里面,先发送A请求,然后等待服务器做出回应,收到后再发出B请求。管道机制则是允许浏览器同时发出A请求和B请求,但是服务器还是按照顺序,先回应A请求,完成后再回应B请求。
虽然1.1版允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的。服务端是按队列顺序处理请求的,服务器只有处理完一个回应,才会进行下一个回应。假如前面的请求处理时间很长,后面就会有许多请求排队等着,这样就造成了“队头阻塞”的问题。
为了避免这个问题可以减少请求数,或者同时多开持久连接。SPDY也允许给每个request设置优先级,这样重要的请求就会优先得到响应。比如浏览器加载首页,首页的html内容应该优先展示,之后才是各种静态资源文件,脚本文件等加载,这样可以保证用户能第一时间看到网页内容。
一个TCP连接现在可以传送多个回应,势必就要有一种机制,区分数据包是属于哪一个回应的。这就是Content-length字段的作用,声明本次回应的字节长度。后面的字节就属于下一个回应了。
- 分块传输编码
使用Content-Length字段的前提条件是,服务器发送回应之前,必须知道回应的数据长度。而对于一些很耗时的动态操作来说,这意味着,服务器要等到所有操作完成,才能发送数据,显然这样的效率不高。更好的处理方法是,产生一块数据,就发送一块,采用"流模式"(stream)取代"缓存模式"(buffer)。
因此,1.1版规定可以不使用Content-Length字段,而使用"分块传输编码"(chunked transfer encoding)。只要请求或回应的头信息有
Transfer-Encoding: chunked,就表明回应将由数量未定的数据块组成。
每个非空的数据块之前,会有一个16进制的数值,表示这个块的长度。最后是一个大小为0的块,就表示本次回应的数据发送完了。例如:
HTTP/1.1 200 OK
Content-Type: text/plain
Transfer-Encoding: chunked
25
This is the data in the first chunk
1C
and this is the second one
4
last
0
- 断点续传
定义了断点续传相关的HTTP头 Range和Content-Range字段,一个最简单的断点续传实现大概如下:
1.客户端下载一个1024K的文件,已经下载了其中512K
- 网络中断,客户端请求续传,因此需要在HTTP头中申明本次需要续传的片段:
Range:bytes=512000-
通知服务端从文件的512K位置开始传输文件
- 服务端收到断点续传请求,从文件的512K位置开始传输,并且在HTTP头中增加:
Content-Range:bytes 512000-/1024000
并且此时服务端返回的HTTP状态码应该是206,而不是200。
HTTP/2.0
- 多路复用
即不仅客户端能够同时发送多个请求,服务端也能同时处理多个请求,而且不用按照顺序一一对应。解决了队头堵塞的问题。
举例来说,在一个TCP连接里面,服务器同时收到了A请求和B请求,于是先回应A请求,结果发现处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。
多路复用.jpg- 数据流
因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的回应。因此,必须要对数据包做标记,指出它属于哪个回应。
HTTP/2 将每个请求或回应的所有数据包,称为一个数据流(stream)。每个数据流都有一个独一无二的编号。数据包发送的时候,都必须标记数据流ID,用来区分它属于哪个数据流。另外还规定,客户端发出的数据流,ID一律为奇数,服务器发出的,ID为偶数。
数据流发送到一半的时候,客户端和服务器都可以发送信号(RST_STREAM帧),取消这个数据流。1.1版取消数据流的唯一方法,就是关闭TCP连接。这就是说,HTTP/2 可以取消某一次请求,同时保证TCP连接还打开着,可以被其他请求使用。
客户端还可以指定数据流的优先级。优先级越高,服务器就会越早回应。
- 服务器推送
HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送(server push)。
意思是说,当我们对支持HTTP2.0的web server请求数据的时候,服务器会顺便把一些客户端需要的资源一起推送到客户端,免得客户端再次创建连接发送请求到服务器端获取。这种方式非常合适加载静态资源。
常见场景是客户端请求一个网页,这个网页里面包含很多静态资源。正常情况下,客户端必须收到网页后,解析HTML源码,发现有静态资源,再发出静态资源请求。其实,服务器可以预期到客户端请求网页后,很可能会再请求静态资源,所以就主动把这些静态资源随着网页一起发给客户端了。
服务端推送能把客户端所需要的资源伴随着index.html一起发送到客户端,省去了客户端重复请求的步骤。正因为没有发起请求,建立连接等操作,所以静态资源通过服务端推送的方式可以极大地提升速度。
服务器推送.png- 二进制协议
HTTP/1.1 版的头信息肯定是文本(ASCII编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为"帧"(frame):头信息帧和数据帧。
HTTP 请求和响应报文
HTTP 请求报文
一个HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据4个部分组成:
HTTP请求报文.png- 请求行(request line)
请求行由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。例如,GET /index.html HTTP/1.1。
HTTP/1.1的请求方法有9种:
GET 请求指定的页面信息,并返回实体主体。
HEAD 类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头
POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和/或已有资源的修改。
PUT 从客户端向服务器传送的数据取代指定的文档的内容。
DELETE 请求服务器删除指定的页面。
CONNECT HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。
OPTIONS 允许客户端查看服务器的性能。
TRACE 回显服务器收到的请求,主要用于测试或诊断。
PATCH 是对 PUT 方法的补充,用来对已知资源进行局部更新 。
- 请求头部(header)
请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。请求头部通知服务器有关于客户端请求的信息,典型的请求头有:
User-Agent:产生请求的浏览器类型。
Accept:客户端可识别的内容类型列表。
Host:请求的主机名,允许多个域名同处一个IP地址,即虚拟主机。
- 空行
最后一个请求头之后是一个空行,发送回车符和换行符,通知服务器以下不再有请求头。
- 请求数据
请求数据不在GET方法中使用,而是在POST方法中使用。POST方法适用于需要客户填写表单的场合。与请求数据相关的最常使用的请求头是Content-Type和Content-Length。
HTTP 响应报文
HTTP响应报文由三个部分组成:状态行、消息报头、响应正文:
HTTP响应报文.png- 状态行
状态行由HTTP版本号,状态码(Status-Code)和原因组成。根据状态码可以知道返回信息的状态。状态码规定如下:
1xx: 信息响应类,表示接收到请求并且继续处理
100——必须继续发出请求
101——要求服务器根据请求转换HTTP协议版本
2xx: 处理成功响应类,表示动作被成功接收、理解和接受
200——交易成功
201——提示知道新文件的URL
202——接受和处理、但处理未完成
203——返回信息不确定或不完整
204——请求收到,但返回信息为空
205——服务器完成了请求,用户代理必须复位当前已经浏览过的文件
206——服务器已经完成了部分用户的GET请求
3xx: 重定向响应类,为了完成指定的动作,必须接受进一步处理
300——请求的资源可在多处得到
301——删除请求数据
302——在其他地址发现了请求数据
303——建议客户访问其他URL或访问方式
304——客户端已经执行了GET,但文件未变化
305——请求的资源必须从服务器指定的地址得到
306——前一版本HTTP中使用的代码,现行版本中不再使用
307——申明请求的资源临时性删除
4xx: 客户端错误,客户请求包含语法错误或者是不能正确执行
400——错误请求,如语法错误
401——未授权
402——保留有效ChargeTo头响应
403——禁止访问
404——没有发现文件、查询或URl
405——在Request-Line字段定义的方法不允许
406——根据发送的Accept,请求资源不可访问
407——用户必须首先在代理服务器上得到授权
408——客户端没有在指定的时间内完成请求
409——对当前资源状态,请求不能完成
410——服务器不再有此资源且无进一步地址
411——服务器拒绝用户定义的Content-Length
412——一个或多个请求头字段在当前请求中错误
413——请求的资源大于服务器允许的大小
414——请求的资源URL长于服务器允许的长度
415——请求资源不支持请求项目格式
416——请求中包含Range请求头字段,在当前请求资源范围内没有range指示值,请求也不包含If-Range请求头字段
417——服务器不满足请求Expect头字段指定的期望值,如果是代理服务器,可能是下一级服务器不能满足请求长。
5xx: 服务端错误,服务器不能正确执行一个正确的请求
500——内部服务器错误
501——未实现
502——网关错误
HTTPS
HTTP 有着一个致命的缺陷,那就是内容是明文传输的,没有经过任何加密,而这些明文数据会经过WiFi、路由器、运营商、机房等多个物理设备节点,如果在这中间任意一个节点被监听,传输的内容就会完全暴露,这一攻击手法叫做MITM(Man In The Middle)中间人攻击。
HTTPS基于HTTP协议,通过SSL或TLS提供加密处理数据、验证对方身份以及数据完整性保护。
HTTPS的加解密流程
HTTPS.png- 用户在浏览器发起HTTPS请求,默认使用服务端的443端口进行连接;
- HTTPS需要使用一套CA数字证书,证书内会附带一个公钥Pub,而与之对应的私钥Private保留在服务端不公开;
- 服务端收到请求,返回配置好的包含公钥Pub的证书给客户端;
- 客户端收到证书,校验合法性,主要包括是否在有效期内、证书的域名与请求的域名是否匹配,上一级证书是否有效(递归判断,直到判断到系统内置或浏览器配置好的根证书),如果不通过,则显示HTTPS警告信息,如果通过则继续;
- 客户端生成一个用于对称加密的随机Key,并用证书内的公钥Pub进行加密,发送给服务端;
- 服务端收到随机Key的密文,使用与公钥Pub配对的私钥Private进行解密,得到客户端真正想发送的随机Key;
- 服务端使用客户端发送过来的随机Key对要传输的HTTP数据进行对称加密,将密文返回客户端;
- 客户端使用随机Key对称解密密文,得到HTTP数据明文;
- 后续HTTPS请求使用之前交换好的随机Key进行对称加解密。
怎么保证保证服务器给客户端下发的公钥是真正的公钥,而不是中间人伪造的公钥呢?
-
问题的描述:
中间人篡改公钥.png
出现这一问题的核心原因是客户端无法确认收到的公钥是不是真的是服务端发来的。为了解决这个问题,互联网引入了一个公信机构,这就是CA。
服务端在使用HTTPS前,去经过认证的CA机构申请颁发一份数字证书,数字证书里包含有证书持有者、证书有效期、公钥等信息,服务端将证书发送给客户端,客户端校验证书身份和要访问的网站身份确实一致后再进行后续的加密操作。
但是,如果中间人也聪明一点,只改动了证书中的公钥部分,客户端依然不能确认公钥是否被篡改。
- 解决的方法
数字证书认证机构(CA,Certificate Authority)是客户端与服务器双方都可信赖的第三方机构。
服务端在使用HTTPS前,去经过认证的CA机构申请颁发一份数字证书(申请时发出自己的公钥Pub),申请到的数字证书里包含有证书持有者、证书有效期、公钥等信息,服务端再将证书发送给客户端,客户端校验证书身份和要访问的网站身份确实一致后再进行后续的加密操作。
具体过程如下:
1.(签名,Signing)CA机构拥有自己的一对公钥和私钥
2.(签名,Signing)CA机构在颁发证书时对证书明文信息Data以服务端公钥Pub作为输入,进行哈希,得到一个特有的Hash值。
3.(签名,Signing)将Hash值用CA机构私钥进行加签得到数字签名Signature,并将该签名与服务端公钥Pub,CA证书明文绑定到一起
4.(认证,Verification)客户端得到证书,分解得到服务端公钥Pub,明文部分Data和数字签名Signature
5.(认证,Verification)用CA机构的公钥对数字签名进行解签,得到Hash值(由于CA机构是一种公信身份,因此在系统或浏览器中会内置CA机构的证书和公钥信息)
6.(认证,Verification)用证书里声明的哈希算法和服务端公钥Pub对明文Data部分进行哈希得到Hash
7.(认证,Verification)当自己计算得到的哈希值与解签后的Hash值相等,表示证书和服务端公钥都可信,没有被篡改
网友评论