HTTP 协议基础概念复习
回顾一下发现本科学的东西都忘了,网络好像是那个说脏话的爱尔兰人教的,总之脑子里全是烤羊腿和老雪。这里重新整理一下。
内容:
- 介绍
- http在TCP/IP协议栈中的位置
- HTTP的请求响应模型
- 工作流程
- 抓包
- Http 报文格式
- Http/1.0 和Http/1.1 的区别
- Cookie和Session
- 缓存的实现原理
- 断点续传和多线程下载的实现原理
- HTTPS 原理简介
1. 介绍
HTTP是Hyper Text Transfer Protocol(超文本传输协议)的缩写。它的发展是万维网协会(World Wide Web Consortium)和Internet工作小组IETF(Internet Engineering Task Force)合作的结果,(他们)最终发布了一系列的RFC,RFC 1945定义了HTTP/1.0版本。其中最著名的就是RFC 2616。RFC (Request for Comments) 2616定义了今天普遍使用的一个版本——HTTP 1.1。 http/1.0 和 http/1.1 还是有很明显的区别的。后面再说
HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传送协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。(和网页的内容的表现形式有关,图片是通过url来定位的,文字先加载,图片再一次http请求,加载得到之后再加载)
HTTP是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型。HTTP是一个无状态的协议。(<mark>无状态指的是状态无记录,通过session或者cooki这种东西来实现有状态</mark>)
2. http在TCP/IP协议栈中的位置
HTTP协议通常承载于TCP协议之上,有时也承载于TLS或SSL协议层之上,这个时候,就成了我们常说的HTTPS。如下图所示:
<mark>默认HTTP的端口号为80,HTTPS的端口号为443</mark>.
3. HTTP的请求响应模型
HTTP协议永远都是客户端发起请求,服务器回送响应。见下图:
这样就限制了使用HTTP协议,无法实现在客户端没有发起请求的时候,服务器将消息推送给客户端。
HTTP协议是一个无状态的协议,同一个客户端的这次请求和上次请求是没有对应关系。
4. 工作流程
一次HTTP操作称为一个事务,其工作过程可分为四步:
- 首先客户机与服务器需要建立连接。只要单击某个超级链接,HTTP的工作开始。
- 建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是MIME (Multipurpose Internet Mail Extensions) 信息, 包括请求修饰符、客户机信息和可能的内容。
- 服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息, 包括服务器信息、实体信息和可能的内容。
- 客户端接收服务器所返回的信息通过浏览器显示在用户的显示屏上,然后客户机与服务器断开连接。
如果在以上过程中的某一步出现错误,那么产生错误的信息将返回到客户端,有显示屏输出。对于用户来说,这些过程是由HTTP自己完成的,用户只要用鼠标点击,等待信息显示就可以了。
5. 抓包
Mac 使用 Charles 等
Windows 使用 Wireshark 等
6. Http 报文格式
6.1 请求报文
一个HTTP请求报文由请求行(request line)
、请求头部(header)
、空行
和请求数据
4个部分组成,下图给出了请求报文的一般格式。
-
请求行 请求行分为三个部分:请求方法、请求地址 和 协议版本.
请求方法:
HTTP/1.1 定义的请求方法有8种:GET、POST、PUT、DELETE、PATCH、HEAD、OPTIONS、TRACE。
最常的两种GET和POST,如果是RESTful接口的话一般会用到GET、POST、DELETE、PUT。HTTP/1.0 只定义了三种 GET, HEAD, POST请求地址:
URL:统一资源定位符,是一种自愿位置的抽象唯一识别方法。
组成:<协议>://<主机>:<端口>/<路径>
端口和路径有时可以省略(HTTP默认端口号是80)
如下例:协议版本:
协议版本的格式为:HTTP/主版本号.次版本号,常用的有HTTP/1.0和HTTP/1.1 -
请求头部
请求头部为请求报文添加了一些附加信息,由“名/值”对组成,每行一对,名和值之间使用冒号分隔。
常见请求头如下:请求头部的最后会有一个空行,表示请求头部结束,接下来为请求数据,这一行非常重要,必不可少。
-
请求数据
可选部分,比如GET请求一般就没有请求数据。
下面是一个POST方法的请求报文:
POST /index.php HTTP/1.1 请求行
Host: localhost
User-Agent: Mozilla/5.0 (Windows NT 5.1; rv:10.0.2) Gecko/20100101 Firefox/10.0.2 请求头
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer:http://localhost/
Content-Length:25
Content-Type:application/x-www-form-urlencoded
//空行//
username=aa&password=1234 请求数据
6.2 响应报文
HTTP响应报文由状态行
、响应头部
、空行
以及响应数据
组成。
-
状态行
由3部分组成,分别为:协议版本,状态码,状态码描述 三个。
其中协议版本与请求报文一致,状态码描述是对状态码的简单描述。-状态码:
状态代码为3位数字。
1xx:指示信息——表示请求已接收,继续处理。
2xx:成功——表示请求已被成功接收、理解、接受。
3xx:重定向——要完成请求必须进行更进一步的操作。
4xx:客户端错误——请求有语法错误或请求无法实现。
5xx:服务器端错误——服务器未能实现合法的请求。
-协议版本:
协议版本的格式为:HTTP/主版本号.次版本号,常用的有HTTP/1.0和HTTP/1.1
据两个例子:
HTTP/1.1 200 OK
HTTP/1.1 200 Connection established
-
响应头部
与请求头部类似,为响应报文添加了一些附加信息
常见响应头部如下:
请求头部的最后会有一个空行,表示请求头部结束,接下来为请求数据,这一行非常重要,必不可少。
-
响应数据
用于存放需要返回给客户端的数据信息。
下面是一个响应报文的实例:
HTTP/1.1 200 OK 状态行
Server: Tengine/2.0.2 响应头部
Date: Thu, 13 Sep 2018 11:17:28 GMT
Content-Type: text/html;charset=UTF-8
Transfer-Encoding: chunked
X-ASEN: SEN-9877428
Cache-Control: no-cache, must-revalidate
Expires: Thu, 01 Jan 1970 00:00:00 GMT
X-Confluence-Request-Time: 1536837448721
X-Seraph-LoginReason: OK
X-AUSERNAME: zhangyu02_sx
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
Proxy-Connection: keep-alive
-----空行-----
<!DOCTYPE html> 响应数据
<html>
.......
</html>
6.3 HTTP 首部字段根据实际用途被分为以下 4 种类型。
通用首部字段(General Header Fields)
请求报文和响应报文两方都会使用的首部。请求首部字段(Request Header Fields)
从客户端向服务器端发送请求报文时使用的首部。补充了请求的附加内容、客户端信息、响应内容相关优先级等信息。响应首部字段(Response Header Fields)
从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息。实体首部字段(Entity Header Fields)
针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间等与实体有关的信息。
-
通用首部字段
首部字段名 说明
Cache-Control |控制缓存的行为
Connection |逐跳首部、连接的管理
Date |创建报文的日期时间
Pragma |报文指令
Trailer |报文末端的首部一览
Transfer-Encoding| 指定报文主体的传输编码方式
Upgrade |升级为其他协议
Via |代理服务器的相关信息
Warning |错误通知
请求首部字段...
响应首部字段...
-
实体首部字段
首部字段名 |说明
---------|------
Allow |资源可支持的HTTP方法
Content-Encoding| 实体主体适用的编码方式
Content-Language| 实体主体的自然语言
Content-Length |实体主体的大小(单位:字节)
Content-Location| 替代对应资源的URI
Content-MD5 |实体主体的报文摘要
Content-Range |实体主体的位置范围
Content-Type |实体主体的媒体类型
Expires |实体主体过期的日期时间
Last-Modified |资源的最后修改日期时间
7. Http/1.0 和Http/1.1 的区别
7.1 RFC1945定义了HTTP/1.0版本,RFC2616定义了HTTP/1.1版本。
7.2 建立连接方面
HTTP/1.0 每次请求都需要建立新的TCP连接,连接不能复用。HTTP/1.1 新的请求可以在上次请求建立的TCP连接之上发送,连接可以复用。优点是减少重复进行TCP三次握手的开销,提高效率。
<mark>注意:在同一个TCP连接中,新的请求需要等上次请求收到响应后,才能发送。</mark>
这是因为,
在http1.1,request和reponse头中都有可能出现一个connection的头,此header的含义是当client和server通信时对于长链接如何进行处理。
在http1.1中,client和server都是默认对方支持长链接的, 如果client使用http1.1协议,但又不希望使用长链接,则需要在header中指明connection的值为close;如果server方也不想支持长链接,则在response中也需要明确说明connection的值为close。不论request还是response的header中包含了值为close的connection,都表明当前正在使用的tcp链接在当前请求处理完毕后会被断掉。以后client再进行新的请求时就必须创建新的tcp链接了。
7.3 Host域
HTTP1.1在Request消息头里头多了一个Host域, HTTP1.0则没有这个域。
Eg.:
GET /pub/WWW/TheProject.html HTTP/1.1
Host: www.w3.org
可能HTTP1.0的时候认为,建立TCP连接的时候已经指定了IP地址,这个IP地址上只有一个host。
7.4 日期时间戳
(接收方向)
无论是HTTP1.0还是HTTP1.1,都要能解析下面三种date/time stamp:
Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
(发送方向)
HTTP1.0要求不能生成第三种asctime格式的date/time stamp;
HTTP1.1则要求只生成RFC 1123(第一种)格式的date/time stamp。
7.5 状态响应码
状态响应码100 (Continue) 状态代码的使用,允许客户端在发request消息body之前先用request header试探一下server,看server要不要接收request body,再决定要不要发request body。
客户端在Request头部中包含
Expect: 100-continue
Server看到之后呢如果回100 (Continue) 这个状态代码,客户端就继续发request body。这个是HTTP1.1才有的。
另外在HTTP/1.1中还增加了101、203、205等等性状态响应码
7.6 请求方法,上面提到过
HTTP1.1增加了OPTIONS, PUT, DELETE, TRACE, CONNECT这些Request方法
8. Cookie和Session
Cookie和Session都为了用来保存状态信息,都是保存客户端状态的机制,它们都是为了解决HTTP无状态的问题而所做的努力。
Session可以用Cookie来实现,也可以用URL回写的机制来实现。用Cookie来实现的Session可以认为是对Cookie更高级的应用。
8.1 两者比较
Cookie和Session有以下明显的不同点:
1)Cookie将状态保存在客户端,Session将状态 保存在服务器端;
2)Cookies是服务器在 本地机器上存储的小段文本 并随每一个请求发送至同一个服务器。
Cookie最早在RFC2109中实现,后续RFC2965做了增强。网络服务器用HTTP头向客户端发送cookies,在客户终端,浏览器解析这些cookies并将它们保存为一个本地文件,它会自动将同一服务器的任何请求缚上这些cookies。Session并没有在HTTP的协议中定义;
3)Session是针对每一个用户的,变量的值保存在服务器上,用一个sessionID来区分是哪个用户session变量,这个值是通过用户的浏览器在访问的时候返回给服务器,当客户禁用cookie时,这个值也可能设置为由get来返回给服务器;
4)就安全性来说:当你访问一个使用session 的站点,同时在自己机子上建立一个cookie,建议在服务器端的SESSION机制更安全些.因为它不会任意读取客户存储的信息。
8.2 Session机制
Session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个客户端的请求里是否已包含了一个session标识 - 称为 session id,如果已包含一个session id, 则说明以前已经为此客户端创建过session,服务器就按照session id 把这个 session 检索出来使用(如果检索不到,可能会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个 session id将被在本次响应中返回给客户端保存。
8.3 Session的实现方式
-
使用Cookie来实现
服务器给每个Session分配一个唯一的JSESSIONID,并通过Cookie发送给客户端。
当客户端发起新的请求的时候,将在Cookie头中携带这个JSESSIONID。这样服务器能够找到这个客户端对应的Session。
流程如下图所示: -
使用URL回显来实现
URL回写是指服务器在发送给浏览器页面的所有链接中都携带JSESSIONID的参数,这样客户端点击任何一个链接都会把JSESSIONID带会服务器。
如果直接在浏览器输入服务端资源的url来请求该资源,那么Session是匹配不到的。
Tomcat对Session的实现,是一开始同时使用Cookie和URL回写机制,如果发现客户端支持Cookie,就继续使用Cookie,停止使用URL回写。如果发现Cookie被禁用,就一直使用URL回写。jsp开发处理到Session的时候,对页面中的链接最好使用response.encodeURL(),原因你懂的。
8.4 与Cookie相关的HTTP扩展头
- Cookie:客户端将服务器设置的Cookie返回到服务器;
- Set-Cookie:服务器向客户端设置Cookie;
- Cookie2 (RFC2965)):客户端指示服务器支持Cookie的版本;
- Set-Cookie2 (RFC2965):服务器向客户端设置Cookie。
8.5 Cookie的流程
服务器在响应消息中用Set-Cookie头将Cookie的内容回送给客户端,客户端在新的请求中将相同的内容携带在Cookie头中发送给服务器。从而实现会话的保持。
流程如下图所示:
9. 缓存的实现原理
9.1 缓存的优点
- 减少相应延迟:因为请求从缓存服务器(离客户端更近)而不是源服务器被相应,这个过程耗时更少,让web服务器看上去相应更快。
- 减少网络带宽消耗:当副本被重用时会减低客户端的带宽消耗;客户可以节省带宽费用,控制带宽的需求的增长并更易于管理。
9.2 与缓存相关的HTTP扩展消息头
- Expires:指示响应内容过期的时间,格林威治时间GMT
- Cache-Control:更细致的控制缓存的内容
- Last-Modified:响应中资源最后一次修改的时间
- ETag:响应中资源的校验值,在服务器上某个时段是唯一标识的。
- Date:服务器的时间
- If-Modified-Since:客户端存取的该资源最后一次修改的时间,同Last-Modified。
- If-None-Match:客户端存取的该资源的检验值,同ETag。
9.3 客户端缓存生效的常见流程
服务器收到请求时,会在200OK中回送该资源的Last-Modified和ETag头,客户端将该资源保存在cache中,并记录这两个属性。当客户端需要发送相同的请求时,会在请求中携带If-Modified-Since和If-None-Match两个头。两个头的值分别是响应中Last-Modified和ETag头的值。服务器通过这两个头判断本地资源未发生变化,客户端不需要重新下载,返回304响应。常见流程如下图所示:
9.4 缓存机制
HTTP/1.1中缓存的目的是为了在很多情况下减少发送请求,同时在许多情况下可以不需要发送完整响应。前者减少了网络回路的数量;HTTP利用一个“过期(expiration)”机制来为此目的。后者减少了网络应用的带宽;HTTP用“验证(validation)”机制来为此目的。
HTTP定义了3种缓存机制:
1)Freshness:允许一个回应消息可以在源服务器不被重新检查,并且可以由服务器和客户端来控制。例如,Expires回应头给了一个文档不可用的时间。Cache-Control中的max-age标识指明了缓存的最长时间;
2)Validation:用来检查以一个缓存的回应是否仍然可用。例如,如果一个回应有一个Last-Modified回应头,缓存能够使用If-Modified-Since来判断是否已改变,以便判断根据情况发送请求;
3)Invalidation: 在另一个请求通过缓存的时候,常常有一个副作用。例如,如果一个URL关联到一个缓存回应,但是其后跟着POST、PUT和DELETE的请求的话,缓存就会过期。
10 断点续传和多线程下载的实现原理
- HTTP协议的GET方法,支持只请求某个资源的某一部分;
- 206 Partial Content 部分内容响应;
- Range 请求的资源范围;
- Content-Range 响应的资源范围;
- 在连接断开重连时,客户端只请求该资源未下载的部分,而不是重新请求整个资源,来实现断点续传。
分块请求资源实例:
E.g.1:Range: bytes=306302- :请求这个资源从306302个字节到末尾的部分;
E.g.2:Content-Range: bytes 306302-604047/604048: 响应中指示携带的是该资源的第306302-604047的字节,该资源共604048个字节;
客户端通过并发的请求相同资源的不同片段,来实现对某个资源的并发分块下载。从而达到快速下载的目的。目前流行的FlashGet和迅雷基本都是这个原理。
多线程下载的原理:
- 下载工具开启多个发出HTTP请求的线程;
- 每个http请求只请求资源文件的一部分:Content-Range: bytes 20000-40000/47000;
- 合并每个线程下载的文件。
11 HTTPS 原理简介
-
客户端发起HTTPS请求
这个没什么好说的,就是用户在浏览器里输入一个https网址,然后连接到server的443端口。
-
服务端的配置
采用HTTPS协议的服务器必须要有一套数字证书,可以自己制作,也可以向组织申请。区别就是自己颁发的证书需要客户端验证通过,才可以继续访问,而使用受信任的公司申请的证书则不会弹出提示页面(startssl就是个不错的选择,有1年的免费服务)。这套证书其实就是一对公钥和私钥。如果对公钥和私钥不太理解,可以想象成一把钥匙和一个锁头,只是全世界只有你一个人有这把钥匙,你可以把锁头给别人,别人可以用这个锁把重要的东西锁起来,然后发给你,因为只有你一个人有这把钥匙,所以只有你才能看到被这把锁锁起来的东西。
-
传送证书
这个证书其实就是公钥,只是包含了很多信息,如证书的颁发机构,过期时间等等。
-
客户端解析证书
这部分工作是有客户端的TLS来完成的,首先会验证公钥是否有效,比如颁发机构,过期时间等等,如果发现异常,则会弹出一个警告框,提示证书存在问题。如果证书没有问题,那么就生成一个随即值。然后用证书对该随机值进行加密。就好像上面说的,把随机值用锁头锁起来,这样除非有钥匙,不然看不到被锁住的内容。
-
传送加密信息
这部分传送的是用证书加密后的随机值,目的就是让服务端得到这个随机值,以后客户端和服务端的通信就可以通过这个随机值来进行加密解密了。
-
服务端加密信息
服务端用私钥解密后,得到了客户端传过来的随机值(私钥),然后把内容通过该值进行对称加密。所谓对称加密就是,将信息和私钥通过某种算法混合在一起,这样除非知道私钥,不然无法获取内容,而正好客户端和服务端都知道这个私钥,所以只要加密算法够彪悍,私钥够复杂,数据就够安全。
-
传输加密后的信息
这部分信息是服务段用私钥加密后的信息,可以在客户端被还原
-
客户端解密信息
客户端用之前生成的私钥解密服务段传过来的信息,于是获取了解密后的内容。
给一张图:
整个过程第三方即使监听到了数据,也束手无策。