HTTP的基本格式详解
在我之前的文章中,给大家介绍过TCP/IP五层协议栈中的几个常见协议。今天再给大家补充一下一个基于TCP协议的应用层协议HTTP。HTTP协议也是日常开发中非常常用的的一种协议,在众多协议栈里HTTP可能是实际开发中用的最多的。所以我们在这一块一定要重视起来
注:这里说的HTTP是指HTTP1以及HTTP2,他们都是基于TCP协议的,注意:如今最新版的HTTP3是基于UDP的。 但是如今在互联网中使用的最多的仍然是HTTP1.1的版本。
在整个协议栈中,上层和下层之间的关系是一定的关联关系的,上层协议要调用下层协议,下层协议要给上层协议提供一个支撑,所以说HTTP作为一个应用层协议,他在进行传输数据的时候,就要基于TCP的这一套机制的保证。
传输层协议,主要关注的是端对端之间的数据传输,TCP,重点关注的是可靠传输。 应用层协议,则是站在程序应用的角度,要对传输的数据,来进行具体的使用~很多时候是程序猿们自定制的,根据实际的需求场景,来设计协议。 但是,程序猿大的圈子里,水平参差不齐~~于是有些大佬们就发明了一些很好用的协议,直接让大家照搬,HTTP就是其中的一个典型代表。 HTTP虽然是已经设计好的,自身的可拓展是非常强的,可以根据实际需要,让程序猿传输各种自定义的数据信息~
HTTP具体的应用场景:大家天天都在用的浏览器,只要你打开浏览器,随便打开一个网站,这个时候其实你就用到了HTTP或者你打开一个手机APP,随便加载一些数据,这个时候其实你大概率也就用到了HTTP。
HTTP协议格式
接下来我们来讲解一下关于HTTP的协议的格式
协议格式:数据具体是怎么组织的 例如: 我们之前讲的UDP:报头(源端口,目的端口,长度,校验和)+荷载 TCP/UDP/IP这些协议都是属于二进制的协议,经常要理解到二进制的bit位~~ HTTP则是一个文本格式的协议。(不需要去理解具体的二进制位,而只是理解文本的格式即可)。文本格式更便于人肉眼来观察。
那么我们又要如何才能看到HTTP的报文格式呢?
其实可以借用一些“抓包工具”来获取到具体的HTTP交互过程中的请求和响应~~
其实咱们前面讲TCP/UDP这些,也是可以借助抓包工具来分析的~~
抓包工具,其实就是一个第三方的程序~,在这个网络通信的过程中,类似于代理一样 抓包工具其实有非常非常多的。我这里给大家介绍一个我自己常用并且认为非常好用的抓包工具(Fiddler),Fiddler是一个专门抓HTTP的抓包工具~(没法抓到 TCP/UDP/IP),要想要抓到这些,需要使用像wireshark这样的工具。
fiddler抓包工具的基本用法
首先我们可以先去官网下载一个fiddler,然后打开就可以自动帮你抓包~~非常方便 Fiddler左侧是一个列表,显示了当前抓到的所有的HTTP/HTTPS的数据报
HTTPS是HTTP的孪生兄弟,HTTPS就只是在HTTP的基础上,引入了加密机制,以后再详细介绍。
当选中左侧列表中的某个条目,并且双击的时候,右侧就会显示这个条目的详细信息。 之后我们再选择Raw这个选项,看到的就是HTTP请求数据的本体,选择其他的选项,相当于是Fiddler对数据进行了一些加工,调整了格式 如果你觉得这个原始数据的字体太小了,可以点击下面的这个选项,用记事本打开。 以上就是HTTP请求的原始模样,如果你往TCPsocket中,按照上述格式来构造数据,并写入socket,其实本质上就相当于构造了一个HTTP请求。 针对响应,也有很多的选项,此处要选择Raw,才能看到本体~~
看到的本体好像是乱码??乱码其实是压缩之后的结果~~ 一个服务器,最贵的硬件资源,其实是网络带宽,像这些HTTP响应,经常会很大,就比较占用带宽,为了能够提高效率,经常服务器会放回“压缩之后”的数据,由浏览器收到之后再来解压缩~~
在我们学会了如何简单的使用抓包工具之后,我们来随便抓几个来研究一下HTTP的协议的格式。 先来看看HTTP的请求
HTTP请求
请求分成四个部分: 1.请求行(首行),包含三个部分 a)HTTP的方法,方法大概描述了这个请求想要干什么~~,GET意思就是想要从服务器获取到某个东西 b)URL描述了要访问的网络上的资源具体是在哪~~ c)版本号,HTTP/1.1表示当前使用的HTTP版本是1.1,1.1是目前最流行的版本。 2.请求头(header)包含了很多行,每一行都是一个键值对,键和值之间用空格来分割,这里的键值对个数是不固定的,有可能多也有可能少,不同的键值对,表示的含义也不同。 3.空行 ,相当于请求头的结束标记~~ 4.请求正文(body)可选的,不一定会有。
HTTP请求的详解
了解了上面的HTTP请求的基本格式之后,我们来逐个的讲解一下具体的含义
URL
URL含义就是“网络上唯一资源的地址符“(既要明确主机是谁,又要明确具体是主机上的哪个资源) 通过浏览器,打开网页的时候,地址栏里填写的这个”网址“其实就是 URL 例如: 我们随便打开一个网站(搜狗) 其实这就是一个URL. 我们还可以再来试试在搜狗里面搜索别的内容 例如:搜索一个哔哩哔哩 现在他是不是就变成了一个长长的一串字 URL小结: 对于URL来说,里面的结构看起来比较复杂,其实最重要的,和我们实际开发最关系紧密的,主要就是四个部分 1)IP地址/域名 2)端口号(经常是小透明) 3)带层次结构的路径 4)query string查询字符串~~
方法
HTTP协议的方法是非常多的,但是最最常用的也就是GRT和POST方法
HTTP中引入这些方法,初衷是为了表达不同的语义 例如: HTML中(h3,p,a,img)这样的语义化标签,(div,span)无语义标签 但是!!!理想很丰满,现实却很骨感,设计HTTP的大佬希望程序猿能够按照HTTP语义来使用这里的各种方法,但是随着时间的推移,使用就开始走形了,现在大家写代码,基本都是GET/POST一把梭~~基本无视掉了语义的事情,正因为如此,也就导致了多种HTTP方法之间的界限,就变得模糊了。 GET也可以给服务器送东西 POST也可以从服务器拿东西。
这里就不得不讲一下一个经典的面试题了:谈谈GET和POST的区别
首先我们需要明白的是,GET和POST是没有本质的区别的,具体来说,相当于是GET能使用的场景,也能替换成POST,POST能使用的场景,也能替换成GET 但是细节上,还是有一些区别的 1.语义上的区别,GET通常用来取数据,POST通常用来上传数据(现状是,GET也经常用来上传数据,POST也经常用来获取数据) 2.通常情况下,GET是没有body,GET通过query string 向服务器传递数据。 通常情况下,POST是有body的,POST通过body向服务器传递数据,但是POST 没有query string 如果我就想让GET有body(自己构造),或者就想让POST带有query sring 也是完全可以的 3.GET请求一般是幂等的,POST请求一般是不幂等的 《幂等:每次你相同的输入,得到的输出结果是确定的》 《不幂等:每次你相同的输入,得到的结果不确定》 4.GET可以被缓存,POST不能被缓存,相当于提前把结果记住了~~如果是幂等的,记住结果是很有用的,节省了下次访问的开销,如果不是幂等的,就不应该去记。
header
header里面都是一些键值对,不同的键值对就代表了不同的含义,这里的种类比较多和杂,我们就挑选出几种常见的来简单介绍一下。
关于Content-Length的补充 HTTP也是基于TCP的协议,TCP是一个面向字节流的协议,会出现粘包问题==》合理设计应用层协议,来明确包和包之间的边界(HTTP中都有体现) 1.使用分隔符 2.使用长度 如果当前有若干个GET请求,到了TCP接受缓冲区了,应用程序读取请求的时候,就以空格作为分隔符 如果当前是有若干个POST请求,到了TCP缓冲区,这个时候,空行后面还有body~~当应用程序读到空行之后,就需要按照Content-Length表明的长度,继续若干长度的数据
User-Agent (UA)
以前的时候,由于浏览器发展很快,导致市场被严重割裂了,一部分用户,用的是比较老旧的浏览器(只能显示文本),一部分用户,用的是比较新的浏览器(能够支持js),这个时候就给网站开发人员带来了挑战~~
为了解决这个问题,聪明的程序猿就想到了,让浏览器发送的请求中,来自报家门~~服务器就可以根据浏览器中的这个自报家门的信息,就可以做出区分了。
在2022年的今天,主流的浏览器的功能已经差别很小(十年前,浏览器的兼容性,还是前端开发要考虑的大问题)UA这个字段起到的作用就已经不那么大了,但是随着当下移动互联网的到来,UA现在又有了新的使命:用来区分是PC端还是手机端,最大的区别就是屏幕的尺寸和比例!!屏幕尺寸是远远小于PC端,屏幕比例PC都是宽屏,手机都是窄屏,比例不同就导致页面布局就得不同~因此,服务器就可以根据UA来区分当前是手机端还是PC端,如果是手机就返回手机版的网页,如果是电脑就返回电脑版的网页
Referer 表示了当前的页面,是从哪个页面,跳转过来的
Referer不是一定有的~~如果你是通过浏览器地址栏直接输入地址或者直接点收藏夹,这个时候是没referer
这个时候可能很多人就蒙圈了,那这个具体有啥用呢?其实这个是一个非常有用的字段
我们现在用到Referer主要是用来广告计费,比如你在搜狗的浏览器里面点击了一个广告,其实都会先访问搜狗的服务器,再跳转到广告主的页面,一点击就把这个请求发送给了搜狗的计费服务器,搜狗就可以按照这个服务器上收到的数据来进行统计。广告主那边也同时进行记录一些日志。当然一个广告主,可能在多个平台投放广告,广告主就可以通过Referer来区分当前的请求是哪个广告平台导入过来的流量
这里可能有些滑稽老铁们可能就会心生一计,是否有一种操作~~把HTTP请求中的Referer给篡改了?本来是搜狗的,改成了别的,然后间接的赚别人的钱? 其实这种操作是完全可以的,而且还一度非常猖獗,那么谁有能力和动机去干这件事情呢?—>运营商(电信,移动,联通),运营商也有自己的广告平台,网络基础设备都是运营商提供的,网络流量经过了人家的设备,人家的设备就可以对你的请求进行抓包,并且可以进行修改操作,运营商劫持事件在2015年前是非常普遍的,到如今基本就不存在这样的问题了,各大广告平台都使用了HTTPS协议进行加密了。
Cookie Cookie就是浏览器给页面提供的一种能够持久化存储数据的机制(持久化指的是,数据不会因为程序重启或者主机重启而丢失)
Cookie具体的组织形式: 1.先按照域名来组织,针对每个域名,分别分配一个小房间,例如我访问搜狗,浏览器就会给sogou这个域名记录一组cookie, 2.一个小房间里面,又会按照键值对的方式来组织数据 Cookie里面保存身份信息,这件事情,就类似于去医院看病,第一次去医院的时候,我们需要办理一张就诊卡,给你就诊卡的时候,人家工作人员就会问你要你的具体的信息(姓名,身份证号码,手机号码。。),后续的看病的过程,这个就诊卡就发挥了至关重要的作用,看病之前要刷一下你的就诊卡,就可以获取到你的信息(姓名,性别,以往的病例),后续拍片,验血之类医生也给你开好了,你可以直接去相对于的科室,然后拿着你的就诊卡刷一下,就知道要拍啥样的片。
上述过程中,我手里的就诊卡就是cookie,虽然就诊卡上面可以存储一些信息,但是保存的数据量是有限的,真正保存我的这些信息,并不是这张卡,而是放到了医院的服务器上,而卡上只需要存储我的一个身份标识(存一个用户id),这些关键信息,存储在服务器上,管这个东西称为”session“会话,服务器这里管理着很多的session,每个session里面都存储了用户的关键信息,每个session也有一个sessionID,就诊卡上其实存储的就是这个会话的id。
Cookie最重要的应用场景,就是存储会话id,进一步让访问服务器的后续页面的时候,能够带上这个id从而让服务器能够知道当前用户的信息(服务器上保存用户信息这样的机制就称为session会话)
关于Session会话的理解,有点类似于QQ的消息列表,消息列表就相当于这里的会话列表
HTTP响应
1.首行:包含了3个部分 a)版本号~HTTP/1.1 b)200状态码,描述了这个响应,是一个表示“成功的”还是”失败的“,以及不同的状态码所描述的状态的信息 c)OK状态码的描述,通过一个/一组简单的单词,来描述当前状态码的含义~~ 2.响应头(header)也是一个键值对的结构,每个键值对占一行,每个键和值之间使用:空格来分割,响应头中的键值对个数也是不确定的,不同键值对表示的含义不同。 3.空行,表示响应头结束标记 4.响应正文(body)服务器返回给客户端的具体的数据,这里的东西可能有各种不同的格式~~其中最常见的格式就是HTML
HTTP响应详解
状态码
表示这次请求是成功还是失败,以及失败的原因是啥
这里随便列出几种,遇到实际情况的时候可以百度具体分析
一般情况下: 2开头,都属于成功 3开头,都属于重定向 4开头,都属于客户端出现错误 5开头,都属于服务器出现错误了 这些状态码中,还有一个特别好玩的,418状态码,虽然你可能百度查不到,但是确实是存在于HTTP标准文档中,大家可以感兴趣的话可以去看看,描述的是:I am a teapot 我是一个茶壶,这其实是一个彩蛋~~(程序猿的幽默哈哈),我们平时也代码还是尽量别写进去,避免出现一些无法预知的错误
正文
正文(body),里面的格式非常灵活,取决于响应头中的Content-Type 1)html 2)css 3)js 4)json
其余的格式基本上与请求中的类似,就不再重复讲了
|