1.HTTP协议学习背景
在之前的学习中,我们已经学习过了TCP/UDP/IP等协议,但是这些协议在TCP/IP五层协议栈中位于传输层,传输层协议更注重端对端的数据传输,例如TCP更关注的是可靠传输,以网购为例,传输层类似于网店商家,他们只关注物品是否送到了客户的手里,但是却不关注客户用这个商品做什么,这时,应用层协议就需要工作了,因为我们将来在工作时,其实接触的基本上都是应用层,应用层协议一般都是程序员自己写的,但是不同程序员水平参差不齐,这时就有优秀的程序员开发出了模板,HTTP协议,我们就可以根据实际需要让程序员传输各种自定义的数据信息
2.HTTP协议概述
HTTP是一个文本格式的协议,因此不需要去像TCP/UDP那样去理解具体的二进制位,理解文本格式即可
可以通过抓包工具来分析获取到HTTP的报文格式,抓包工具是一个第三方程序,类似于代理,代理就是中间的传话人,请求和响应都需要路过代理,因此就很容易在代理这里获取传输过程中网络上的详细内容
3.使用Fiddler抓包HTTP协议
我们在这里使用Fiddler这个抓包软件,下载好之后打开其
程序左边显示的是抓到的各种HTTP,双击某一条HTTP后右边会出现这个HTTP的具体内容,上半部分是请求,下半部分是响应,我们都选择Raw这个选项来看请求和响应,因为Raw意味原始的,未经加工的,我们这个时候看到的就是最原始的HTTP样子,响应部分有时会显示为乱码(因为网络部分最贵的硬件资源是带宽,HTTP响应一般都很大,十分占用带宽,这时服务器经常会返回压缩之后的数据,由浏览器收到之后再解压缩),这时我们通过黄色的条选项来解压缩
(使用fiddler可以 全选,之后delete删除左边列表的数据)
4.HTTP的基本格式
(1)请求格式
请求分为四个部分:
1.请求行(首行包括1,2)
通常显示了该条HTTP协议的方法,也就是这条HTTP想做什么,例如GET,想从服务器上获取某个东西,POST想向服务器发送某个东西
经典面试题:GET和POST的区别
本质上来说,GET和POST没有区别,因为两个方法在任何使用场景都可以互相替换,也就是说可以用GET就可以用POST,反之亦然,但是在细微处还是存在一些区别:
1.语义上,GET通常用来为获取数据,POST通常用来为上传数据
2.通常情况下,方法为GET的HTTP是没有body部分的,因为GET使用URL的query string部分来向服务器传递数据,燃而POST是通过body来向服务器传数据的,因此POST有body但是没有query string部分,不过这个只是一个习惯用法,并不是强制性的区别
3.通常情况下,GET请求是幂等的,POST是不幂等的(这个只是建议用法而不是强制用法),幂等性就是如果是相同的输入,那么得到的输出一定是确定不变的,不幂等的话就是相同的输入得到的输出是不确定的
4.如果按3来进行规定,那么GET就可以被缓存,POST不可以被缓存,因为3中说到GET是幂等的,那么相同输入的结果已经确定,这个时候将其缓存可以方便下次访问,而POST结果不确定,缓存就显得没有意义了
一般上执行登录操作都是用POST操作,但是POST和GET方法并没有本质区别,为什么我们还要选择POST呢
因为GET请求向服务器传输的数据默认储存在URL中的query string中,那这个时候就会使得URL很长,用户的观感很差,同时很多浏览器早期都是明文提交数据在query string中,这样造成安全性也不是很好,而POST请求默认是将数据储存在body中的,用户无法直接看到,并且会对于body进行加密,这样一来无论观感还是安全性上都有所提高,但是这并不意味着GET方法安全性比POST方法差,能够影响安全性的因素只有是否是明文提交数据的,并不是方法差异
2.URL
URL描述了要访问的网络资源的位置
URL的含义就是“网络上唯一资源的地址符”,通过URL既要明确访问的主机是谁,也要明确访问的是这个主机上的什么内容
URL的组成:
1.协议方案名,如http:// 描述了当前URL是给哪个协议使用的
2.服务器地址:表示当前要访问的服务器主机是什么,可以是服务器的IP地址,也可以是服务器域名
3.端口号:表示当前要访问的主机上的哪个应用程序 大部分情况下是省略的,省略不是说没有,而是浏览器自动给了赋予了一个默认值,对于http开头的URL就会使用80作为默认值,https使用443为端口默认值
4.文件路径:描述了当前要访问的服务器资源是啥,但是不一定服务器就真的存在一个对应文件,这个文件可能是一个真实的在磁盘上存在的文件,也可能是虚拟的由服务器代码构造的动态数据
5.query string(查询字符串):通过上述的IP地址 + 端口 + 带层次的文件路径其实就描述了一个网络上的具体资源,但是在这个具体资源之上,也可以带一些具体参数,例如查询字符串,本质上是浏览器/客户端给服务器传递的自定义的信息,相当于对获取到的资源提出了进一步的要求,查询字符串和路径之间用?隔开,查询字符串本身也是一个一个的键值对结构键值对中键和值用=隔开,不同键值对用&符号隔开
6.片段标识符:描述了要访问当前html页面中哪个具体的字部份,能够控制浏览器滚动到相关位置
URL小结,对于URL来说虽然看起来复杂,但其实对于开发最重要的是:1.IP地址/域名 2.端口号 3.带层次结构的路径 4.query string 查询字符串 3和4和写代码密切相关
urlencode/urldecode:
当query string中包含特殊字符,就需要对特殊字符进行转义,这个转义过程就叫url encode,反之就叫url decode 因为url里面是有很多的特殊含义符号 例如? 如果查询字符串中也有这种符号那么很容易解析失败 urlencode 的规则就是把要转义的内容的ascii码值(二进制)取出来同时加上%
在网页上搜索c++,其中的“++”就被urlendode转义为了%2B%2B
3.版本号:HTTP/1.1 表示当前使用的HTTP版本是1.1 1.1是当下最火的版本,也可能是1.0/2/3
4.请求头(header)包含了很多行
每一行都是一个键值对 键和值之间使用 :空格来分割 这里的键值对个数是不固定的,有可能多有可能少,不同的键和值表示的含义也不同
1.HOST:表示主机的地址和端口
2.Content-Length:表示body中的数据长度
3.Content-Type:表示body中的数据格式
2,3都是针对有body的HTTP协议,如果没有body的话自然也就没有2,3,引入Conten-Length是因为HTTP也是基于TCP的一个协议,而TCP是一个面向字节流的协议,这时就会涉及到“粘包问题”,在传输时数据一个字节一个字节的粘在一起储存在接收缓冲区内导致TCP无法分辨包与包的界限,解决粘包问题最好的办法是(1)使用分隔符,例如HTTP中的空行在GET请求中应用程序读取请求的时候就会以空行为分隔符,(2)使用长度,例如Content-Length,POST请求到了接收缓冲区时读到空行之后还有body,因此就需要按照Content-Length表明的长度继续读取若干长度的数据
4.User-Agent(UA):表示的是当前用户是在拿什么东西来上网,主要是操作系统信息+浏览器信息 随着当下移动互联网的到来,UA又有了新的使命,用来区分PC端还是手机端
5.Referer:表示了当前的页面是从哪个页面跳转过来的
6.Cookie:浏览器给页面提供的一种可以持久化存储数据的机制(不会因为程序重启或者主机重启而丢失(写到了用户电脑的磁盘里))
浏览器为了安全默认情况下是不能让页面的JS访问到用户电脑上的文件系统,但是这样的安全限制也带来一些麻烦,例如说登录操作,存储用户当前的身份信息,当用户在登录页面完成身份认证之后,服务器会给浏览器返回一个用户的身份信息,浏览器将身份信息储存在一个特定位置上,后续再访问同个网站的不同页面时,浏览器自动的带上这个身份信息,服务器就可以识别了,就不需要再登录,这个特定位置,类似于一个小黑屋,是磁盘给浏览器单独分出来的一篇空间,页面的js可以在这个小黑屋里随意访问操作,但不会影响到除这个空间外的其他空间,这个小黑屋有很多种不同的形式,Cookie就是一个比较古老比较经典的形式
Cookie具体的组织形式:
1.先按照域名来组织,针对每个域名分别分配一个小房间
2.一个小房间里面又会按照键值对的方式来组织数据
Cookie中储存用户信息的机制称为session(会话),每一个session都有自己的sessionId,服务器只需要识别用户传来
的sessionId就可以访问到这个用户储存了的具体信息
5.空行 相当于请求头的结束标记类似于链表的null
6.请求正文(body)
是可选的,不一定会有,一般方法为POST的会有body,GET的不会有body
(2)响应格式
响应也分为四个部分
1.状态行(首行)
首行包含三个部分:版本号,状态码和状态码的描述
版本号:HTTP/1.1 当下最火的就是HTTP/1.1
状态码:200 状态码表示了这个响应成功或者失败,不同的状态码代表不同的失败原因
状态码以2-5不同的数字开头都有不同的含义:
以2开头:这一系列都代表请求成功,典型的就是200
以3开头:这一系列都代表为重定向,需要用户采用进一步行动才能继续,重定向就意味着跳转到某一个新的地址,常见的例如302,在登录操作时我们经常遇到,其中的Location就代表了接下来要跳转的目的地址
以4开头:这一系列代表客户端错误,常见的如404 Not Found,表示要访问的资源不存在,403 Forbidden,表示虽然该资源存在,但是用户没有权限去访问,405 Method Not Allowed等
以5开头:这一系列很少遇到,意味着服务器出现了错误,例如500 Internal Server Error,服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器端的源代码出现错误时出现
状态码的描述:OK 通过一个或者一组简单的单词来描述当前状态码的含义
2.响应头(header)
响应头也是键值对结构,每个键值对占一行,每个键和值之间使用:空格来分隔,响应头中的键值对个数也是不确定的不同键值对表示不同含义,其中常见的和请求中一样
3.空行 表示响应头的结束标记
4.响应正文(body)
服务器返回给客户端的具体数据,其中可能有不同的格式,但是最常见的就是html,还可能有css,js,json这几种格式
这里是将代码压缩用以节省带宽了,因此我们看到的是一串乱码
5.构造HTTP请求
1.基于html的form表单构造http请求
1.构造form标签,填写action,method属性:
其中,action中的数据就是要将请求提交到哪里,是一个URL,method就是意味着你想用什么方法来进行提交数据
2.搭配form中拥有的其他标签
其中用到了input标签的name属性,因为我们向服务器提供数据时本质是利用键值对来提交的,那么其中的name标签就意味着提交的数据中的key,用户在input标签中输入的内容就是键值对的value
3.写一个提交按钮
利用input标签 submit属性来写一个提交按钮
我们点击提交后,页面会跳转到action中的目的地址
观察url可以发现,我们利用GET方法提交的数据,储存在了url的query string当中,以键值对的形式储存
如果我们将method改为post,那么提交的数据就会储存在body之中
但是基于form表单构造HTTP请求的方式比较原始,其中一定涉及到了页面的跳转操作,随着前端页面的发展,越来越复杂,跳转加载整个页面效率变低了,我们可以不让整个页面加载出来而只需要加载其中需要变化的一小部分,因此我们就可以用Ajax来构造HTTP请求
2.基于Ajax构造HTTP请求
通过js代码构造请求并且用js处理响应,然后将得到的数据更新到页面上
同步(阻塞等待和非阻塞等待)和异步的区别
同步(synchronized):
同步等待是我们要主动的关注和等待结果
同步阻塞式等待:我们在提交请求等待结果时,无法做任何事情,只可以等待结果反馈回来之后进行下一步操作
同步非阻塞式等待:我们在提交请求后,可以做其他的事情,但是每个一段时间后就要主动的查询结果是否反馈回来了,之后进行下一步操作
异步(asynchronous):
异步等待就是我们不需要主动的关注和等待结果,我们提交了请求之后,直接去做其他的事情,等结果好了会主动通知我们
因为Ajax全名为Asynchronous Javascript And XML,因此其中用到的等待方式是异步等待,构造出HHTP请求后发给服务器,但是浏览器并不确定服务器何时才能有响应,因此浏览器就直接继续执行其他代码,当服务器响应结果反馈回来后再有浏览器通知相关的js代码,采用回调函数的方式处理响应
我们通过jQuery来编写HTTP请求
1.引入jQuery
2.通过$对象调用ajax函数
3.运行
当我们直接运行后,发现并没有跳转,反而报错了
这是因为ajax不支持跨域访问,当前这个页面的服务器是本地文件,但是访问的目的页面是sogou服务器,因此就会造成访问失败