HTTP协议("超文本传输协议"),是一个被广泛使用应用层协议,自1991年正式发布HTTP协议以来,HTTP协议就一直在更新,目前已经更新到3.0版本,但是目前主流的依旧是1.1版本,但依旧是一个最主流使用的应用层协议。
HTTP协议一般是基于TCP协议实现的,当时知道HTTP3.0开始支持UDP协议实现传输,使用TCP相比较UDP虽然安全,但是速度却相差很多,从3.0版本开始支持UDP协议,为了的实现更快的传输,并且该版本在应用层实现了可靠传输的机制,保证了高速传输的同时,也保证可靠传输。
HTTP协议格式
HTTP是⼀个⽂本格式的协议.可以通过Chrome开发者⼯具中的network功能或者Fiddler抓包,分析HTTP请求/响应 的细节。
Fiddle抓包基础
1. HTTP请求报文
HTTP请求报文一般包含首行,请求头(header),空行,正文(body,可能有,可能没有)
1.2.1 首行
首行一般包含3部分,请求方法 ,url (服务器资源唯一定位符),HTTP协议版本。
发展到现在HTTP协议的请求方法有很多种,包括GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS,意思是表示让服务器知道这个请求是要干嘛的,其中最常见最重要的就是GET,POST方法。可以说GET占八斗,POST占一斗,其余占一斗。
1.2.1.1 url
了解HTTP协议应该从了解url开始,可以认为你所看到的每一个网页,都有一个唯一的url,也就是我们通常说所的网址,以下是由RFC文档对url进行了约定https://datatracker.ietf.org/doc/html/rfc1738虽然看起来它是由很多部分组成的,但是实际组成很简单。
- 1.协议名称:https,为什么是https而不是http,后面会解释,可以先理解它是http协议的安全版本;
- 2.身份认证信息(目前已经舍弃,这里也没有体现):只要是因为现在网站进行身份认证都是简单通过url提交身份信息;
- 3.服务器域名(ip地址):www.baidu.com,这里有时候会是一个ip地址,也有可能是一个域名,但是实际指的都是同一个服务器;
- 4.服务器端口号(可以省略):指的是要访问服务器的哪个端口号,现在可以省略是因为规定好了,如果是http协议就固定访问80端口号,是http是协议就访问443端口号,除非有些特定的资源就可能会需要指定端口号,不然一般都是上述两个端口号;
- 5.带层次的文件路径:描述的是服务器管理的资源
- 6.查询字符串:通常是一些键值对,键和值之间用"=",键值对之间用"&"分隔开;
- 7.片段标识符:片段标识符可以表示网页中的一部分,一个网页可能有很多部分组成,有时候你点一个标题或者什么,会自动跳到这个网页的某个部分。
关于URL encode
不知道你有没有发现,有时候你搜索东西,在网址哪里会显示你输入的关键词,有时候却没有,比如我现在搜索一个C++,query string的value是c%2B%2B,是因为有时候value有时候也会有符号,如果不进行转码,可能就会出现类似"粘包问题",所以需要对某些字符进行转码。但是使用什么转码才能确保不会出现问题呢?如果是汉字使用utf8和gbk,转码后的字节可能会与特殊的字节重复,所以用的另一套转码规则--"urlencode",在这套规则中,如果遇到需要转码的字符,就会按照这套规则将字符转码,用十六进制表示,并在前面加上一个"%",以表示这是一个转码后的,也是为了能够分开。但是又时候你看到的并不是转码后的,而是实际你输入的搜索内容,这是因为浏览器为了让客户看到,实际在传输的内容还是转码后的内容。
1.2.1.2 请求方法
HTTP协议首行最先出现的就是请求方法,可以让服务器知道这个请求时要干什么的?到目前为止,请求方法包括:GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS,有一种说法:GET占八斗,POST占一斗,其余占一斗,说的就是GET和POST的重要性,我们最经常使用的也是这两种方法。
GET和POST的区别
- 1.本质上是没有区别的;
- 2.从语义和一般传递数据的方式来看是有一定区别的:GET语义上是从服务器上获取资源,所以通常GET请求不会带有正文,因为正文一般是要发送个服务器的数据的,一般GET请求向服务器提交数据是通过query string键值对去提交数据,像我们搜索,搜索内容就是query string这个键值对的value提交给服务器,而POST请求一般是要通过正文提交的,而不是通过query string传输数据。但是随着现在网络的使用,get和post的界限已经很模糊了,get请求可以搭配body使用,post也可以搭配query string 使用。
- 3.服务器对GET请求时幂等的,对POST请求是不幂等的。(幂等就是多次请求返回的结果是一样的),GET请求是可以缓存的(保存收藏夹),POST请求是不可以缓存的(跟幂等也有一定的关系),POST请求一般是获取到了服务器的302临时重定位,再向服务器发给GET请求,获取到网络主页的内容。
几个有问题的说法
1.POST比GET安全
该说法的论证就是使用GET请求,url会显示提交的个人信息,被人看到造成信息泄露,而POST是通过正文(body)提交信息,看不到,所以比GET安全。
这个说法是很有问题,实际上我们通过抓包工具也可以很简单的获取到信息,传输数据安不安全不取决显不显示,而是取决是否对信息加密。
2.GET请求提交的数据量有限,比较短,POST请求提交的数据量比较多,不限制。该说法它的论据是GET是通过url的Query String提交数据的,而POST是通过正文提交数据的,主要是因为但是IE浏览器确实是对URL长度做出了限制,但是这是很早的情况了,现在的HTTP协议对url的长度是不做限制的,所以该说法也是不正确的。
3.GET只能传输文本数据,POST既可以传文本,又可以传二进制数据。实际上url有encode转码机制,只要对二进制进行encode转码,也可以传输二进制数据。
1.2.1.3 HTTP协议版本
在首行的最后,通常会有一个 HTTP/1.1,表明使用的HTTP协议的版本。
1.2.2 请求头(header)
在HTTP的协议中,在首行和空行之间的就是请求头(header),通常都是一些标准规定的键值对内容,键和值之间用":",键值对之间用";",由于有很多的键值对,这里只介绍重要的键值对。
Host
客户端要访问的服务器的IP地址和端口号,有时候没有端口号,只有一个域名或者IP地址,这一部分一般是跟URL中的服务器域名和端口号是一样的。
Content-Type
表示请求中的正文中的数据格式,为的是针对不同的数据类型,服务器能够选择不同的处理方式,针对音频有音频的处理方式,图片有图片的数据方式。
Content-length
表示正文的长度,使得服务器能够知道完整的正文长度,防止"粘包问题"。
User-Agent (简称UA)
表示浏览器/操作系统的属性;
Referer
表示这个页面是从哪个页面跳转来的,如果是直接输入url或者点击收藏夹里的访问,是没有Referer这个键值对的。
Cookie(Header最重要的一个键值对)
cookie包含了很多的键值对,键和值之间用:,键值对之间用;其中的键值对都是开发网站的程序员自定义的,除了他自己能看懂,其他人都看不懂;
Cookie本质上是永久化保存在硬盘上的,但是网页是在浏览器上运行的,如果直接让网页操作硬盘是非常危险的,意为着有可能有一个网站都有可能直接获取到硬盘的数据,所以浏览器对于硬盘的操作,做了严格特殊的封装,硬盘中提供了一个/一组文件来给网页保存内容,而且对于保存格式了做了严格的规范,只能保存键值对,键和值都必须是文本数据;浏览器就给网页提供了能够持久化保存数据的一个经典机制---cookie,不同的网站都有不同的Cookie。
Cookie的来源:在一开始访问服务器的请求中是没有cookie,第一次出现Cookie是出现在响应中的header中set-cookie中,浏览器收到响应之后就会把set-cookie中的内容保存为cookie中;
Cookie的去处:等到再次访问服务器的时候,请求的header中就会带上cookie,返回发给服务器,让服务器知道你已经访问过服务器了,带上了服务器给客户端的一些信息。
Cookie的作用:客户端保存了服务器给的特定的键值对,再访问服务器的时候就会带上cookie,一个服务器要服务很多的客户端,每一个客户端都保存一个这样的cookie,键值对中通常会带上很多重要的数据作为键值对,比如你的网站的配置,像夜间模式/白天模式(让服务器记住你的习惯,等到你再次访问服务器的时候,访问的页面可能就是跟你的使用习惯一样),方便服务器给你提供符文。cookie还有一个特别重要的键值对:key,这是很多网站都会保存的关于客户端的cookie中的个人信息,比如你登录一个网站填上了个人信息,cookie就会保存你的登录信息,就像一张通信证一样,只要有这个cookie,此后你访问网站的每一个网页都不需要再次登录,服务器通过你携带的cookie信息就知道你已经是登陆过的,不要再登录,有权限访问这个网页。像以上服务器保存的id以及相关的各种详细信息就称之会话(session),是一个类/对象;
1.2.3 空行
空行是请求头(header)的结束标志;
1.2.4 正文
正文一般是用来提交信息的,比如你提交一个一个POST请求来上传一个头像,正文的数据就是你头像的二进制数据,但是你通过抓包工具抓到的body保存的是不是图片的二进制格式,而是将二进制数据进行base64转码;
2 HTTP响应报文
HTTP响应报文一般包含状态码,响应报头(header),空行,正文
1.状态码
从状态码可以知道你这次请求的结果,通常由一个数字代码和一个/一组单词组成。状态码有很多种,这里只是分享常用的常见的状态码,详细可以自行百度。
200 OK
这表示这个访问请求成功,这是一个最常见的状态码;
404 Not Found
表示这次请求要访问的资源不存在,或者在客户端不存在;
403 Forbidden
表示你这次请求要访问的资源,你没有权限访问。
405 Method Not Allowed
表示这次请求的方法,服务器不支持。(有的服务器不支持POST请求,有的不支持GET请求之类的,就会出现405);
500 Server Error
表示服务器内部错误,可能是代码出现了bug。由于现在的服务器都是"高可用"的,很少会出现内部错误,一个服务器虽然不可能一直都不出错,但是如果有多台服务器,即使一部服务器出错,也有另一台服务器可以用。所以现实中访问很少会出现服务器错误。如果我们自己开发服务器,就可能会经常看到500错误。
504 Gateway Timeout
表示网关服务器访问超时,我们要访问的服务器可能不只是有一台组成的,可能有多台服务器,但是一定有一个入口服务器,就称之为"网关服务器"。通常服务器比较繁忙的时候会出现这样一个问题。
302 Move Temporarily(临时重定向)
我们有时候会发现我要访问网站的时候,回跳到另外一个网站,比如一个网站更信了域名或者IP地址,我们在访问就地址的时候就会自动跳转到新地址,网页登陆跳转的状态码常常就是302。吗,每一个访问都要访问服务器,等待服务器的响应,获取到响应中Location,才能真正的实现网页的跳转。
301 Moved Permanently(永久重定向)
使用302临时重定向,每一个访问都需要等待服务器的响应,才能实现跳转,这个重定向是临时。而301永久重定向,只要访问一次之后,旧地址和新地址就会形成一种映射保存,此后再次访问都不要通过服务器,直接本地映射跳转。
状态码小结
|-----|------------------------|--------------|
| | 类别 | 原因短语 |
| 1xx | Informational(信息状态码) | 接受的请求正在处理 |
| 2xx | Success(成功状态码) | 请求处理正常完成 |
| 3xx | Redirection(重定向状态码) | 需要进行附加操作完成请求 |
| 4xx | Client Error(客户端错误状态码) | 服务器无法处理该请求 |
| 5xx | Server Error(服务器错误状态码) | 服务器处理请求错误 |
2.响应报头
响应报头的基本格式和请求报头的格式基本⼀致, 类似于 Content-Type , Content-Length 等属性的含义也和请求中的含义⼀致.