一)什么是HTTP协议
1)HTTP协议是倾向于相遇业务层次上面的一种协议,传输层协议主要考虑的是端对端之间的一个传输过程,TCP重点进行关注的是可靠传输;咱们的HTTP/1,HTTP/2是基于TCP的,但是咱们的HTTP/3是基于UDP的,但是当下的互联网绝大多数都是使用的是HTTP/1.1;
无状态:无状态指的是对于请求方的每个请求,接收方都当这次请求是第一次请求
因为对于请求方而言,每次请求时,接收方就像是失忆了一样,并不会依赖请求方以往的请求所生成的数据作回应,也就是说,就像是接收方没有保存请求方的状态(数据)一样,所以叫无状态;
2)但是咱们的应用层协议,主要是站在程序应用的角度,要对传输的数据,做出具体的应用
3)咱们的应用层协议,很多的时候,是咱们的程序员进行自定制的,要根据合适的业务场景来进行设计协议,在程序员这个圈子里面,有些大佬就设计出了很厉害的协议,让咱们的程序自己进行使用,HTTP协议是一个典型代表;
4)HTTP虽然已经是自己设定好的,但是HTTP协议本身的可进行扩展的能力是非常强的,我们就可以根据实际的需求,来程序员来进行传输各种自定义的数据信息;
协议格式:数据具体是如何进行组织的
1)UDP/TCP/IP这些协议都是属于二进制的协议,也就是说经常要理解到二进制的比特位,要想要理解到某一个协议格式,要具体理解到某一个比特位;
2)HTTP则是一个文本格式的协议,不需要去理解具体的二进制位,而是只是需要理解到具体的文本的格式即可,更方便人去理解;
服务器和客户端的交互,分为以下四种模型:
4.1) 一发一收:请求和响应是一一对应的,HTTP协议就是针对这种模型的;
4.2) 多发一收:典型的要传输一个具体的大文件,也就是说多个请求对应到一个响应,要把大文件分成一个个的小文件,多个请求对应到一个响应;
4.3)一发多收:一个请求得到很多响应,例如想要看直播,系统不知道我要看那个直播,就会返回很多响应,返回响应有很多直播供我们来进行选择;
4.4)多发多收:多个请求得到多个响应;
1)HTTP协议:是应用层使用的一种十分广泛的应用层协议,他的全称是超文本传输协议,所谓的超文本,意味着传输的内容不仅仅是文本(例如html,CSS就是文本),还可以是一些其他的资源,例如图片,视频,音频,链接等其他二进制数据,我们使用Servlet是一个构建动态网页的技术,但是HTTP协议是我们前后端进行沟通的一个桥梁;
2)当在浏览器中输入一个网址,此时浏览器就会给对应的服务器发送一个http请求,对方服务器收到这个请求之后,经过计算处理,就会返回一个http响应,这就完成了客户端进行和服务器的一次交互;
3)例如当我们在网络上输入一个网址想要获取搜狗主页,这时就会发一个http请求,经过搜狗服务器的计算之后,这时搜狗的服务器就会返回一个搜狗主页的html;
1)咱们的上面的这些Fidder的抓包的这些标签页的选项,其实本质上就是说当前使用了什么样子的格式来进行显示这个HTTP请求,咱们使用最多的就是这个raw选项;
2)这个raw选项,我们在这里面看到的就是HTTP请求数据的本体,选择其他的选项,就是相当于Fidder对数据整体进行了一些加工,调整了一些格式;
3)上面就是咱们的HTTP请求的原始摸样,如果说你向TCPSocket里面,按照上面的格式来进行构造数据,并且写入到Socket里面,其实本质上就是构建了一个HTTP请求
4)当看到响应报文的时候,发现看到的二进制返回的数据好像是乱码?乱码其实本质上就是压缩之后的结果,咱们的一个服务器本质上来说最贵的就是网络带宽,像咱们的HTTP响应,通常是会很大的,就比较占用网络带宽,但是能够为了提高效率,经常服务器返回压缩之后的数据,咱们的浏览器收到返回回来再来进行解压缩;
通常我们点击这个Response body is encoded,Click to decoded;
1)咱们的Fidder左侧的列表会一直抓到新的结果,会快列表就会很大,因为很多网站都在不同的和服务器之间进行交互,甚至你电脑上面的某一些程序都在偷偷的在和服务器之间进行交互
2)很多时候我们要去进行清屏操作,我们就需要ctrl+a进行全选,然后再按住delete进行删除
这不是说抓包失败,而是抓到了一个请求失败的包
二)HTTP协议的请求格式:
HTTP请求:是一个行文本,一行一行的组织数据,每一行都有特定的含义
HTTP的请求和响应都而是对应着一定的格式的:
HTTP请求格式: 1)首行:方法 + url + 版本号(虽然首行比较长,但是里面分成了三个部分,使用空格来分割); 2)首部请求头(header):这里就是一堆键值对,键值对和键值对之间,使用换行来分割,每一个键值对占一行,键和值之间,使用冒号+空格来分割,header中有多少行,是不确定的;具体是使用一个空行来作为结束标记 请求报头的Key: Value 请求报头的Key: Value 3)空行:用过这个空行来表示header结束了 4)正文body:空行后面的内容都是Body,Body允许是空字符串 如果Body存在,就会在Header里面有一个Content-length属性来表示Body的长度 HTTP响应格式: 1)首行:版本号 + 状态码 + 状态码的解释,他们彼此之间也是使用空格来分割,不同的状态码会有不同的状态码的描述 2)协议头(header):表示请求的属性,冒号+空格来分割键值对;每一个键值对占一行,遇到空行表示Header部分结束; 响应报头Key:Value 响应报头Key:Value 3)空行; 4)Body:空行后面的内容都是Body,Body里面的内容允许是空字符串,如果Body存在,就会在Header中包含一个Content-length的属性来表示Body的长度,如果服务器返回了一个html的界面,那么这个界面的内容就是在Body中
1)为什么这里是一定要有空行的?
因为HTTP协议在本质上是并没有规定报头部分的键值对到底有多少个,空格就相当于报头的结束结束标记,或者是报头域正文之间的分隔符;再说,HTTP在应用层依赖TCP协议,TCP是面向字节流的,如果没有这个空行,就会出现粘包问题;
2)HTTP版本号包括:HTTP/1.1和HTTP/1.0
HTTP请求中的URL,含义就是表示网络上面唯一资源的地址符
1.1)它是用来描述一个网络资源在主机上面的的具体位置,要明确主机是谁,又要进行明确我们是取出网络上面的哪一个资源;
1.2)其实我们通过浏览器,打开网页的时候,地址栏里面填写的地址其实本质上就是一个url
1)协议方案名:描述了说当前的URL是来给哪一个协议来进行使用的,比如说http://就是给HTTP用的,https://是给HTTPS用的,jdbc:mysql://是给jdbc:mysql用的,url是给很多协议来进行使用的,常见的协议名有FTP,HTTPS,jdbc:mysql://可以这么说URL不光仅仅给HTTP协议提供服务,还可以给很多协议提供服务;
2)登录信息:上古时期上网的时候会体现出用户名字和密码,带有登录信息的URL其实现在已经很少见了,现在的登陆一般都是直接搞一个登录界面,在登陆界面里面再去填写用户名和密码,以表单或者ajax的形式来进行提交
3)服务器地址:可以是域名(方便记忆方面传播),还可以是IP地址,表示的是说当前咱们要进行访问的主机是什么?后面可以用一个/来进行分割,IP地址和域名是一一对应的关系,咱们的域名可以经过DNS服务器转化成IP地址;
4)服务器的端口号:表示咱们要进行访问目标主机上面的哪一个应用程序,咱们的这个端口号大部分情况下是省略的,省略的时候不是说没有而是因为浏览器会赋予一个默认值,对于HTTP协议开头的url来说使用的端口就是80端口作为默认值,对于HTTPS的url来说,端口就是被默认指定成为了443,对于一个服务器,绑定的是哪一个端口,这个可是不一定的,如果对方服务器绑定的不是默认端口,那么此时就需要修改了;
5)带层次的文件路径:表示访问服务器上面的不同的资源,一个服务器程序上有很多的资源,我们来找到到底是哪一个资源,也就是要访问的服务器的资源是什么?例如有很多的HTML,有很多的图片,CSS和JS,这个路径往往是带有层次结构的,可能会有一定的目录结构,通过这个目录一层一层的往下找从而找到具体的文件,但是我们还是需要进行注意一下,虽然我们在请求的url里面写的是一个文件路径,但是这个服务器上面对应的却有可能不是一个真实的文件路径,这个文件路径可能说是在磁盘上面的,是一个真实的文件,但是还是有可能是说这个文件路径是由咱们的服务器来构造出来的一个动态数据;
总结:上面的IP地址+端口号+带有层次的文件路径就描述了说一个网络上面的具体的一个资源,IP地址描述了说我们到底要去哪一个快递公司,端口号描述了说我们要去找到快递公司的哪一个工作人员,而我们的带有层次的文件路径就是明确快递公司人员发的取件码
其实在定位网络上的一个具体的资源的,还可以带有其他一些详细的要求,也就是后面的参数部分
6)查询字符串:本质上来说就是咱们的浏览器或者是客户端向服务器传输的自定义的信息,相当于是对获取到的资源提出了一些更高的要求,我们只能看清这里面的格式是什么样子的,但是我们没有办法理解里面键和值都是什么意思,只要特定开发这个应用的程序员才能认识
7)URL中的片段标识符:不是特别常见,通常用于定位HTML页面中的具体位置,这个在文档类网站中,十分常见,以#来进行开始,就是描述了说当前我们要进行访问的html页面中的哪一个具体的子部分,能够控制到浏览器滚动到相关位置,就是类似于快速定位的效果,比如说小说网页,文档网页,一个页面里面有很多的章节,很多的子标题这种,其中我们就可以通过片段标识符来进行跳转到某一个标题或者是某一个片段里面,可以通过片段标识符跳转到一个文档上面的不同章节;
URL的初心就是用来区分网络上的唯一资源:
1)先通过服务器地址,定位到一个具体的服务器;
2)再通过端口号来定位到一个具体的应用程序;
3)再通过路径来定位到应用程序来管理的一个具体资源;
4)再通过查询字符串,对具体资源的要求做出进一步的解释
5)再通过片段标识来确定到定位这个资源的哪个部分;
我们就是说先通过url给定的路径在服务器这里面准备一些相关的资源,然后再根据这里面的查询字符串传递的一些参数再对这些资源来进行处理,进行筛选;
1)当在浏览器上面输入一个搜狗搜索的网址之后,浏览器就会给搜狗的服务器发送了一个HTTP请求,这样咱们的搜狗的服务器就会返回一个HTTP响应;
2)当这个响应结果被浏览器解析之后,就展示成了我们目前所看到的页面内容,这个过程中咱们的浏览器可能会给服务器发送多个HTTP请求,服务器会返回多个响应,这些响应里面就包含了HTML,CSS,JavaScript,图片和字体等信息;
urlncode:当queryString里面出现了特殊字符的时候,就需要对特殊字符进行转义,这个转义的过程,就叫做urlencode
1)反之如果说是把转移的内容进行还原回来,就叫做urldecode,因为咱们的url里面是有很多的特殊含义的符号的,比如说: / ? = &都是具有一定的特定含义的
2)如果浏览器和服务器解析这个URL的时候,就是把URL中的各个部分取出来组织成结构化的数据;
1)在URL当中,有些东西是用户自定义的,典型的就是query string,用户自定义的query string中,是存在着一些特殊符号的: / ? = &,如果query string中也包含着上面的特殊符号,就可能会导致浏览器/服务器进行解析URL的时候出错;
2)例如本来人家程序上面是判定?后面的部分是query string 但是在你的结果里面也有一个?
本来这个?是来进行分隔路径和查询字符串,https://www.sougou.com/web??&_ast?=123456789,咱们的url就不知道从哪里到哪里是完整分割的一部分,我们就把这个特殊和url一样的字符进行转义,避免冲突;
3)稳妥情况下,应该让后面的querystring,不要出现或者包含特殊字符,要是querystring针对特殊字符,直接进行转义(浏览器自动进行转义)
把特殊字符转化成转义字符,叫做URL encode
把转义字符转化成原来的字符,叫做URL decode
除了特殊字符之外,像汉字之类的也要进行URL encode;
下面我们是在搜狗主页输入一个?所构造出来的一个URL;
? - 搜狗搜索https://www.sogou.com/web?query=%3F&_asf=www.sogou.com我们可以看到query=%3F这个就是表示用户输入的查询词,%3F就是URLencode的结果,所谓的转义,就是把这个特殊符号里面的值,按照16进制来进行表示,每一个字节前面加上一个%;
C++ - 搜狗搜索https://www.sogou.com/web?query=C%2B%2B我们在这里面输入C++,浏览器会对+这个字符进行转义,这里面的+对应的ascii的十六进制恰好是2B,也就是说当我们在搜狗页面上面搜索C++的时候,就可以看到url里面的querystring里面,就有了一个键值对,里面就包含了查询内容,这里面的+其实本质上就是针对+本身进行urlencode之后的结果
鲜花 - 搜狗搜索https://www.sogou.com/web?query=%E9%B2%9C%E8%8A%B1在里面输入鲜花,这里面采用了UTF-8编码
所以我们在自己写一个URL的时候,要自己进行URLencode
协议名字+IP地址/域名+端口号+带层次的文件路径+查询字符串+片段标识符
定位到一台主机上面的一个唯一的服务器应用程序上面的资源,查询字符串就是针对这个资源做出了进一步的要求
三)HTTP协议中的方法:
1)DELETE:删除服务器指定资源;
2)OPTIONS:返回服务器所支持的请求方法
3)TRACE:追踪路径
4)CONNECT:要求用隧道协议连接代理
5)HEAD:类似于GET,只返回响应头,不返回响应尾;
6)put方法:传输文件
7)unlink:断开连接关系
8)link:建立和连接之间的关系
GET 请求的参数会保存在历史记录中,而 POST 请求的参数不会保留到历史记录中
一)不同种类的请求,就要用方法来区分,为了区分不同的语义,语义这就表示说有特定的含义,这是属于HTTP协议设定之初的一个初心,把请求根据功能划分成不同的类,随着时间的推移,这些方法已经失去了原有的意义,不同方法之间是可以替换的,进一步来说这些方法之间是没有本质区别的,理论上是可以相互替换的;
比如说h3,p,a,img标签就是语义化标签,但是div,span就是无语义标签
二)例如用GET向服务器里面来提交一个数据是否可以?用GET来删除数据是否可以?这些都是可以的,这不过这两个并不是常见用法,一切的一切都是取决于程序员的代码是如何实现的
三)咱们进行设计HTTP的大佬希望程序员可以按照HTTP的语义来进行使用这里面的各种方法,但是随着时间的推移,我们使用方法使用着使用着就开始走形了,基本上是全部使用的是GET/POST,基本没有考虑过语义的事情,也正因为这样咱们的HTTP请求中的很多方法之间的界限就开始变得模糊了
四)GET和POST之间有什么区别?
都是基于TCP/IP协议来进行实现的,实用两者中的任意一个,都可以进行实现客户端和服务器端的双向交互,没有本质区别,但是在细节上还是有本质区别的
相当于是说咱们GET能够使用的场景,POST也是可以使用的,POST能够使用的场景,一个以替换成POST
1)数据位置:GET通常把自定义数据放到querystring中,POST通常把自定义数据放到body中,GET没有body数据,POST通过body发送数据;
2)语义区别:GET一般用于获取数据,POST一般用于提交数据
3)幂等性:GET请求一般是幂等的,POST请求一般是不会设成幂等的;
4)可缓性:GET请求一般会被缓存(常见的CSS,JS,HTML请求都会被缓存),POST请求一般默认不会缓存,这同样也是取决于程序员的设计,总而言之,这些东西都是可以被打破的,最终的结论还是一句话POST和GET没有本质区别;
5)收藏成标签不同:GET请求的地址可以被收藏为书签POST请求的地址一般不能收藏为书签
6)url的长度限制不同:GET请求的参数是通过url进行传递的,但是url本身的长度是存在限制的,通常是2K,当然不同浏览器厂商不同,版本不同对于url的限制也会不同,但是相同的是他们都会针对于url的大小进行限制,但是POST中的内容请求参数是存放在正文里面的,没有大小限制
7)回退和刷新不同:GET请求可以随便回退和刷新,不会对用户和应用程序产生影响,但是POST请求直接进行回退和刷新会把数据再次进行提交
8)历史记录不同:GET请求一般会保存在历史记录里面,但是POST请求一般不会保存在浏览器记录里面
4)body部分一般不为空,当然如果是空,也是可以的,body里面的数据格式里面可以支持很多种格式,格式的类型,是由请求头中的Content-Type所决定,body的长度,是由请求头中的Content-Length来进行表示
什么是缓存?
1.1)比如说进行一些复杂的计算的时候,得到一些结果,但是如果说这个结果的计算过程代价太大,就可以把这样的结果保存下来,下次直接进行使用,避免进行重复的计算了,GET请求一般是要去要缓存的,POST请求一般是要求不用进行缓存的;
1.2)但是有一种特殊情况,在某些业务条件下,像搜索广告这种,虽然也是GET请求,但是绝对是不可以缓存的(每一个请求一定要是实时计算的);
1.3)咱们的缓存就是就是提前把结果记住,但是如果是幂等的,那么把结果记住是很有用的,这样子就节省了下一次进行访问的开销,但是如果是说不是幂等的,那么就不需要进行记住
1.4)如果请求本身都不是幂等的,那么就不可以缓存,比如说咱们获取到的广告数据虽然也是通过GET请求拿到的,但是绝对不能进行缓存,我们必须要进行实时的计算,我们必须要保证合适的用户出合适的广告,出的广告也是必须要符合广告主的规则,比如说周六不让有广告,但是某个用户在周六收到了广告;
什么是幂等呢?
幂等就是说每一次你进行了相同的输入,得到的输出结果就是确定的;
不幂等就是说每一次你进行了相同的输入,得到的结果就是不确定的;
1.1)这是数学上的术语,某个请求,执行一次和执行多次没有什么区别,如果可以做到这一点,就被称为幂等,例如支付宝里面有查看余额功能,就是幂等的,但是给客户转钱,转账功能,如果不加限制,就不是幂等的;
1.2)像这种转账操作,有时也是需要设计成幂等的,例如有时机器故障,导致服务器收到请求多次,导致进行多次转账,一个简单粗暴的方式就是,给每次转账,都分配一个唯一的身份标识,如果服务器收到很多的相同的身份标识,对其进行去重,那么只执行一次转账,也就是说相同的HTTP数据包多次发送,不会影响客户端的结果;
五)请求报头:
请求的报头中里面的键值对是有很多的,这里面的键值对有些是标准规定的,不同的键值对还有不同的特殊含义,有些是用户自定义的,每个键值对都是独占一行的,键和值使用冒号分隔
1)Host:这是来描述服务器主机的IP地址/端口号,地址可以是域名,也可以是IP,Host里面的东西,其实是和URL中的表示信息是重叠的,一般来说Host中的内容是和URL中的地址是一致的,但是也不是绝对的,因为咱们的域名是可以通过DNS服务器转化成IP地址的;
2)Content-length:表示Body的长度,单位是字节;
3)Content-Type:表示body中的数据格式的类型,告诉服务器要如何解析Body;
上面的这两个属性是在描述body的,如果说你的请求是一个GET请求,而你的请求报文里面没有body部分,也就说明此时不需要Content-Length和Content-Type这两个字段了,一般咱们的POST请求都是带body的;
4)user-Agent:用来表示浏览器操作系统的属性,简称为UA,现在是用来区分PC端和移动端
5)Referer:表示这个页面是从哪里跳转过来的,里面是一个地址;
5.1)这个Referer是不一定有的,像这种直接在浏览器中输入URL,点击收藏夹抓包,抓到的页面请求是没有Referer;
5.2)搜索主页,跳转到搜索结果页,就是带有Referer的,每一个HTTP请求的Referer就是上个跳转的页面;
6)location:搭配3XX状态码来使用,告诉客户端接下来要到哪里去访问;
7)cookie:就是浏览器能够给页面提供的一种可以进行持久化存储的数据的机制
持久化指的是数据不会因为程序重启或者是主机重启而丢失,写到磁盘里面;
1)值是一个字符串,这是程序员自己定义的字符串,Cookie相当于是浏览器自己进行本地储存的一种机制,例如程序员想要让浏览器存储一些信息,就可以使用Cookie;
2)因为我们的浏览器为了安全,默认情况下是不会让咱们的页面上面的JS来进行访问用户的电脑上面的文件系统的,假设在某一个网页上面,包含着恶意代码,我们不小心一点,就很有可能触发这个恶意代码,很有可能就会把你的学习资料全部删除了;
3)浏览器在这里是否要保存信息,储存信息,这是需要的,但是浏览器可不可以把信息写到磁盘文件中,这是万万不可以的,因为可能网页向你的磁盘里面写入一个病毒程序,直接把你的文件全部删除掉了;所以说浏览器是禁止网页直接访问计算机的磁盘的,但在网页开发的时候,我们有希望在网页端保存一些数据(这是客观需求的存在);
4)但是上面的这些安全机制,也存在着一些麻烦,有时候,确实需要说让我们的页面这里面来进行持久化存储一些数据,方便来后续进行访问网站,最典型的就是需要存储用户的一些身份信息,前些日子,我登录CSDN,后续再来些日子还可以显示登录;
1)比如说当我们的用户在登录界面上完成身份认证之后,此时服务器就会返回一个用户的身份信息,浏览器就会把这个信息保存到一个特定的位置上面;
2)后续我们在来进行访问同一个网站上面的其它页面的时候,浏览器就会自动带上这个身份信息,服务器就可以认识这个客户端了;
因此Cookie就是解决上述问题的一个途径,这也是浏览器中存在的一种机制,哪怕机器重启,也会存在,也是让网页进行持久化保存数据的一种方法;
我们可以举一个例子来进行理解一下:
1)我们到医院之后,要先进行挂号,我们要把自己用户的身份信息交给医生,医生会给你发一个就诊卡,这个就诊卡,假设这个卡号是0X123,医生同时也将0X123,和你的身份信息进行组成一个对应关系,放到电脑里面;
Key:0X123 Value:我自己的身份信息,年龄,身高,以往的病历
2)下次去抓药的时候,医生在给你看病之前,直接刷就诊卡,医生得到卡号0X123,刷卡本质上是想要获取我的身份信息,通过电脑保存的映射关系得出你的身份信息,就直接给你开处方药了;
3)那么去药房的时候,就是要刷卡,去打针的时候,还是要进行刷卡,办理其他业务的时候,还是要进行刷卡,那么这张卡就是Cookie,就可以快速的通过这张卡快速的或者去用户身份信息;
Cookie的组织形式:
1)cookie会先按照域名来进行组织,我们针对每一个域名,来进行分配一个比较小的房间,我访问搜狗,浏览器就会按照搜狗的这个域名来进行记录一组Cookie
2)来进行访问码云,浏览器也会给咱们的码云来进行记录一组Cookie
3)在每一个一个小房间里面(一个文件),里面又是会有一些键值对,名称就是相当于是Key,咱们的内容就相当于是Value;
4)Cookie数据是从那里来的?其实本质上是从服务器这里面来的
咱们返回的响应里面其实就包含了上面的这些响应头,其实就是我们的服务器完成身份认证之后,向的客户端返回的一些重要的数据消息,这样的信息就是通过set-Cookie这样的响应报头来进行这样表示的,每一个set-Cookie都是一个键值对;
5)想要查看cookie,可以点击小锁头;
实现持久化存储,保存用户身份标识;
1)实现交互的过程就是从上到下的过程,其实咱们的服务器这里面也会管理着很多很多的Session,这里面的Session里面就是一个哈希表,里面存储着用户的关键信息,比如说基本信息,访问历史等等;
<sessionID,用户的身份信息>
2)实际上有些东西像是sessionID,但是实际上并不知道具体是不是,因为这里面存放的Cookie这里面的键值对,也是和queryString类似,也是程序员自定义的;
3)返回会话ID的前提是当浏览器在向服务器发送数据的时候,服务器就会根据用户名来查询密码确保用户登陆成功的时候才会返回一个set-Cookie字段,里面就包含了用户ID;
总结:Cookie是我们浏览器提供的一个持久化存储数据的机制
1)Cookie最重要的应用场景就是说存储会话的ID,进一步当我们后续再来进行访问服务器的一些页面的时候,从而可以带上这个ID,从而让我们的服务器知道当前的用户信息,服务器上保存用户信息这样的机制我们就称之为是Session会话;
2)Cookie是否可以用来保存别的信息,当然也是可以的,具体想要存放什么信息,都是咱们的程序员进行自定义约定好的;
请求报文中常见的ContentType:
1)application/x-www-form-urlencoded:
这是表单提交的数据格式,每个字段 键=值,此时body中的格式形如:title=test&content=hello;
1.1)键和值之间用=分割,键值对和键值对之间使用&来进行分割,出现%是因为urlencode方式的结果;
1.2)这里面的表单,就是HTML中的form标签,包括input,textarea这些标签都是可以搭配form来进行使用的,form的效果就是与服务器之间进行交互,能够构造出GET/POST请求;1.3)所以说咱们的POST请求的body中的application/x-www-form-urlencoded中的数据格式是和咱们的GET请求中的QueryString的键值对表示的方式是完全相同的;
2)上传文件的时候,multipart/form-data;bounday=....,表单提交的数据格式,在form标签上加上enctyped="multipart/form-data上传文件:
2.1)一般用于请求,不用于响应,其中每个字段可以是简单的数据类型(数值型,字符串,boolean值)
2.2)也可以是复杂的数据类型(图片视频等等)这就意味着form-data可以上传任意多的数据,也可以是多个文件
2.3)bounday表示边界,要传输的数据从哪里开始,到那里是结束3)application/Json body按照Json数据格式来表示
{"username":"123456789","password":"xxxx"}
4)image.jpg:指定一个具体的文件类型,如果客户端发送请求也就只能上传一个文件,如果用于服务器的响应,也就只能返回一个文件;
为什么大家这么喜欢用HTTP协议?
因为HTTP协议的扩展性太好了,非常便于程序员基于这个协议来传输自定义的数据
1)URL中的路径
2)URL中的query string;
3)header中也可以放自定义的键值对
4)body中也可以放自定义的协议
关于HTTP协议一定要注意以下的问题:
1)关于安全,网络安全是指网络被攻击而造成的信息泄露,HTTP是一种明文传输,不会进行任何加密,就直接用最原始的报文来传输,所以在一定程度上,只要是HTTP协议,就是不安全的;
2)关于传输量/URL的长度,长度是有浏览器和web服务器来决定的,在HTTP协议中是没有规范url的长度的;
3)传输的数据类型,POST和GET都是可以传输文本和二进制数据的,就拿一张图片来说,作为为二进制数据使用base64就可以直接编码字符串了
六)请求转发和请求重定向有什么区别?
一)概念不同:
一)请求转发服务器的行为,客户端只给服务器发送了一次请求
发生在服务器端程序内部,当服务器端收到一个客户端的请求之后,会先将请求转发给目标地址,再将目标地址返回的结果转发给客户端,但是客户端是对于这一切是无从感知的
二)请求重定向:(客户端的行为),客户端给服务器发送了两次以上的请求
指的是服务器在收到客户端的请求之后,会给客户端返回了一个临时响应头,这个临时响应头记录了客户端需要再次发送请求重定向的URL地址,客户端收到了地址之后,会将请求发送到新的地址上面
1)比如说现在有一个业务场景,客户端向服务器想要查找数据最终得到一个页面,我们把这个对应的数据删除之后,这个删除操作是Servlet1完成的,服务器向客户端返回删除成功,并返回一个链接地址让后面的客户端再次向服务器发送HTTP请求;
2)然后重定向就是这个客户端给服务器发送了一个HTTP请求,再次请求数据列表页,后端有会对应一个Servlet2,会向数据库查询所有数据返回给前端;
3)请求转发有一种情况,客户端向服务器发送HTTP请求,得到了一些中间数据(查找最终数据的辅助信息),然后Servlet1向Servlet2发送请求,Servlet1带上这些中间数据,最终靠着这些中间数据在Servlet2中查询到了所有数据,Servlet2把数据返回给Servlet1,Servlet1在进行返回给客户端(这些中间数据比如说是ID)
二)现象转发地址栏的地址不会发生改变,但是重定向的地址栏会发生改变,因为发送了两次请求
三)请求转发只能只能访问本应用内的资源,重定向可以访问本应用外的资原;
请求转发:自己写的应用程序,也就是说你这个程序的多个Servlet是可以随意访问的,发送一次请求之后,淘宝的Servlet不能向京东的Servlet发起请求;
比如说现在来了个请求,可以直接重定向到百度页面,但是转发不可以
比如说在某一个浏览器的网站上面,会有一些其他应用的链接,我一点这个链接就到了其他的网站上面去了,这就是重定向;
四)数据共享不同:请求转发是服务器端实现的,所以整个执行流程中,客户端只需要发送一次请求,因此在整个交互过程中都是使用的同一个Request对象和一个Response对象,整个请求的过程中,请求的数据和返回的数据是共享的
但是请求重定向是客户端向服务器发送了两次不同的请求,两次请求中的数据是不同的
5)代码实现不同:
@RequestMapping("/str1) public void start(HttpServletRequest request,HttpServlet response) { return "forward:/blog1.html"; } @RequestMapping("/str2") public void start(HttpServletRequest request,HttpServlet response) { return sendRedirect("/blog1.html"); }
七)301和302有什么区别?
301和302都是表示的是请求重定向的状态码,它们表示请求的资源已经被永久性(301)或者是临时性移动到了另外一个位置,并且客户端应该通过重定向的方式来获取新的资源
301永久重定向:
1)当服务器返回301状态码的时候,表示请求的资源已经永久性的移动到了新的位置
2)当客户端收到301状态码的时候,应该更新书签或者是连接,将原来的url替换成新的url,并且以后的请求都应该是使用新的url来获取资源
3)搜索引擎本身会将301重定向视为是对新的url的引用,将之前的url搜索排名改成新的url
302临时重定向:
当服务器返回302状态码的时候,表示请求的资源暂时性的移动到了新的位置,客户端在收到302响应以后,应该继续使用原来的url来请求资源,而不是使用新的url
八)HTTP协议响应报文的状态码:
咱们的HTTP响应的这些状态码是表示这次请求时成功还是失败,以及失败的原因是什么
1)200 OK这是最常见的一个状态码,表示访问成功;
2)404 Not Found,表示当前访问的资源不存在,每一个请求,都带有一个URL,URL里面都带有一个文件路径像/index.html这个文件路径,这就表示这一次请求想要的资源是什么,表示没有找到资源,在浏览器中输入一个URL,目的是访问对方服务器的上面的一个资源,如果这个URL标识的资源不存在,那么就会出现404,比如说咱们在浏览器上面输入http://www.sougou/1.html;
3)403 Forbidden,或者叫做access denied这是表示访问被拒绝,有的页面通常是用户具有一定的权限才可以进行访问,登录后才可以进行访问,如果用户没有直接登陆后就进行访问,容易出现403,虽然这个资源有,但是你没有权限来进行访问;
4)405 Method Not Allowed方法不支持前面介绍了HTTP中所支持的方法,例如GET,POST等等,但是对方的服务器并不一定支持所有的方法,或者不允许用户使用一些其他的方法,比如说你尝试进行使用GET方法来进行访问人家的服务器,但是人家可能只是支持POST,于是就会返回405;
408:服务器等待客户端发送的请求时间太长,出现超时的情况
411:服务器无法处理客户端发送的不带content-length的请求信息
413:请求的实体过大,服务器无法进行处理因此会拒绝请求,为了防止客户端的连续请求,服务器可能会进行关闭连接
414:表示请求的url过长,服务器无法进行处理
415:服务器无法处理请求附带的媒体格式
5)500 Internal Server Error这是表示服务器内部出现错误出现BUG,或这是服务器的代码中遇到了一些特殊情况(服务器会异常崩溃),这是就会产生这个状态码,在外面服务器上看到这个状态码是比较低的;
6)504 Gateway Timeout表示当服务器负载和比较大的时候,服务器太繁忙了,服务器处理单条请求的时间就会比较长,可能会出现超时的情况,这种情况一般是双十一的时候;
505:远端服务器不支持请求的HTTP协议的版本,无法进行完成处理
504:表示充当网关或者代理的服务器,不能向远端服务器获取请求
503:服务器由于超载或者维护,服务器暂时无法处理客户端的请求
7)302 Move temporarily/Found这是表示临时重定向,别人访问旧的页面自动跳转到新的界面
7.1)类似于呼叫转移,别人呼叫旧的号码自动连接到新密码上,例如我原来的手机号是138-0000-9000,但是我现在换号了,换成了139-0000-9000,这是我需要办理一个呼叫转移业务,这样我的朋友们就不需要知道新号码,当他们拨打我的旧号码的时候,运营商就会自动的转到新的手机号;
7.2)比如在刚才我没有登录我的账号,访问了我的一个私有项目,变成了403,这时我再进行登录,登陆成功后,就会自动的跳转到我的私有项目的那个页面;
7.3)这时在响应报文中的header中会包含一个Location字段,表示要跳转到那个页面哪一个地址上面,客户端就会根据Location中记录的URL,立即进行访问URL;
7.4)对于302这个重定向来说,body不是必须的,对于有些返回的body中,是拥有a标签的,它的作用是万一浏览器没有进行自动跳转那么用户点击这个a标签也可以自己实现手动跳转;
7.5)例如来进行举一个例子,当我们在浏览器上面输入一个不孕不育的时候,会弹出一个a标签,在这个过程中,请求会先打给搜狗的服务器,它会返回一个302响应,浏览器再根据302中的Location字段来决定接下来要去哪里;
8)301:Moved Permanently 表示永久重定向,当浏览器收到这种请求时,后续的请求都会改成新的地址,就不需要先进行访问旧的页面了,301也是通过Location字段来表示需要重定向的新地址,对于重定向来说,他会发送两次请求,这个过程中的url会发生改变
状态码小节:我们要理解上面常见的状态码的含义,还要了解大的类别:
1)1xx表示信息型状态码,接受的请求正在处理;
2)2xx表示成功状态码,表示请求正常,处理完毕;
3)3xx表示重定向状态码,需要进行附加操作才可以完成请求;
4)4xx表示客户端错误状态码表示服务器无法处理请求,418状态码是一个菜单,我是一个茶壶;
5)5xx表示服务器处理错误状态码,服务器请求处理出错;
6)6xx源站没有返回响应头部,只返回实体内容;
先说200,404,302具体的状态码的含义,再去说2xx,3xx,4xx,5xx每一类的含义
我们要知道,一个页面的构成,不仅仅是HTML,他还会依赖很多的资源,例如CSS,JS,图;这些资源都是通过网络来下载到浏览器本地的,但是由于这些资源又大,网络的传输速度又不快,这个时候进行页面加载就会很慢,浏览器然后再把这些依赖的资源直接缓存到本地,再进行后续访问的时候的速度就会变得很快(已经进行缓存的,就不需要再去进行下载了
九)Content-Type:不同的Content-Type在费德勒里面表示的颜色是不一样的;
请求的数据格式和响应的数据格式是不同的,具体取值都不一样;
1))text/html:body的数据格式是html;
2))text/css:body的数据格式是CSS;
3))application/javascript:数据格式是JS;
4))application/json:数据格式是json:
十)HTTP请求的构造:
一)直接在网络上输入一个URL
二)使用form表单,可以构造GET和POST请求
三)使用ajax,构造各种请求
四)也可以通过java代码,基于其中的socket来构造出其中的HTTP请求,进行字符串拼接;
3.1)input标签中的name属性,就构成了querystring中的key;
3.2)input标签输入的内容,就成为了querystring中的value;
3.3)form表单中的method方法,可以控制请求的类型,如果说是按照GET来进行提交,那么参数会放在queryString里面,如果是按照POST来进行提交,那么参数会放在body里面,这里面的method的取值只能是GET或者POST,不区分大小写
action就表示当前要把这个请求发送到哪一个HTTP服务器上面;
4)但是当给百度进行提交请求的时候,百度报错了,这是很正常的,因为百度没有支持像userld,classld这样的参数;必须客户端要和服务器相互配合;
<form action="https://www.baidu.com" method="GET"> <input type="text" name="userID"> <input type="text" name="classID"> <input type="submit" value="提交"> </form>
咱们的form表单来给服务器进行传输的数据本质上应该是键值对,此处的name属性就是在描述当前输入框里面对应的Key是什么,value就是用户在输入框输入的内容,况且光有两个输入框其实还不够,还是需要一个提交按钮来进行触发里面的HTTP请求
最终构建出来的URL就是:https://www.baidu.com/?userID=aa&classID=bb
最终传输的数据类型就是:Content-type=application/x-www-form-urlencoded
通过ajax来构造HTTP请求:
1)form表单的这种方式,其实上是一个比较原始的构造方式,使用form表是会涉及到页面跳转的,浏览器这个时候就会加载出全部页面,这就十分的不科学了,尤其是页面十分复杂的时候,随着前端页面越来越复杂就希望能让整个页面不去进行加载,而是进行加载其中变化的一个小部分就可以了这个时候就可以直接通过JS来构建出一个HTTP请求
2)ajax的全称是Asynchronous JavaScript and XML,以前的时候ajax主要是通过传输XML格式的数据,但是在今天很少会用到XML了;
3)直接通过JS代码来进行构造出一个HTTP请求,再来通过JS代码来进行处理这个响应,并且把得到的一些数据给更新到页面上面;
同步:我提出让他写作业的要求之后,我就一直在这里盯着他写作业,知道他把作业全部完成了,我就在去做其他的事情;
异步:孩子的写作业的时候被我看着压力也挺大,我就只是吩咐了一句,你好好写作业,我就去忙着干其他的事情了,等他写完作业之后,他告诉我了,我再去帮他修改作业,判作业;
在网络编程中数据通过网络传输,主要分成下面两个阶段:
1)等;
2)把数据拷贝过来
等的过程总是给很浪费时间的,不如我们可以用等待的时间,来干一些其它的事情;
1)ajax可以在浏览器渲染页面的时候,进行网络请求,如果没有这种异步机制,那么浏览器要发起网络请求,就会阻塞渲染页面的线程,这样就会导致网络请求中页面被卡死,浏览器不知道啥时候请求可以全部到,就会一直等,但是我们有了异步机制之后,等到渲染页面这两个操作,是可以同时进行的,并且是可以分离开的;
2)所以说在浏览器发送Ajax请求的时候,同时也是在进行其他工作的,当响应回来了之后,浏览器才处理刚才请求的响应;
比如说我想要去叫我女朋友来吃饭:女朋友说马上就来但是可能很久才来,我就需要进行等待
同步的等待:我会一直在这里面等,一会看一眼,一会看一眼,这就类似于说我是调用者,我的女朋友是被调用者,调用者会一直在这里面等着,主动来进行获取到被调用者的结果;
异步的等待:我就直接对他说,我找个凉快地方玩一会手机,一会你下来了给我打电话,当我们的调用者发起一个调用请求之后,就直接不管了,等到被调用者结果出来之后,就会主动通知调用者
咱们的同步等待:
1)阻塞式的等:(不见不散);
2)非阻塞式的等:(每隔一段时间去查询一下结果);
举个例子,假设说我想要去店里面吃饭,我对老板说,来一个蛋炒饭,这个时候就分成三种情况:
1)同步阻塞式等待:
我就蹲在前台这里面,盯着后厨来做饭,直到把饭做好,我自己把饭端走;
2)同步非阻塞式等待:
我在前台这里面看一眼,发现饭没有做好,我于是就出去溜达一圈,过了一会之后我又回到这里面来看,发现饭还是没有做好,于是我就又出去玩了一回手机,经过若干次之后,我发现厨师把饭做好了,我再把饭端走;
3)异步等待:
我就直接啥也不管了,就直接找一个角落坐下,玩手机,该干啥干啥,等到饭好了,人家已经给我端上来了;
第二种和第三种方式都是属于等待的过程中是可以做其他事情的,区别就是在于第二种方式对于调用者来说开销要更大(反复去查询结果),第三种方式往往是更优的;
同步和异步的之间的区别,主要就是看这个结果:
是调用者主动关注,还是被调用者主动来给调用者进行通知,看看是否是调用者主动查询到的,还是调用者被动推送过来的;
阻塞和非阻塞之间的区别,是等待和非等待之间,能不能干别的事情,是不见不散,还是不死等;
在IO的场景中,就会经常涉及到这种情况:
这里面的IO就包含你想要通过
控制台来进行输入输出/通过文件来进行输入输出/通过网络来进行输入输出
1)这里面的ajax就使用异步等待方式,等待被调用者主动推送消息,还可以做其他事;
2)之前学过的Scanner和输入流对象和输出流对象,默认都是同步阻塞等待,一直盯着,主动向被调用者获取消息,像你如果你不输入数据,就没有办法做其他的事情;
AJAX就是通过异步等待的方式来进行的
1)首先浏览器会构造出一个HTTP请求,发送给我们的服务器,但是浏览器不知道什么时候服务器会有响应,于是就先不管了,浏览器就开始继续执行其他代码,该干啥干啥,你响应结果爱回来不回来,不回来都可以;
2)等到我们的服务器把响应返回回来之后,再来有浏览器来通知我们的JS代码,以回调函数的方式来进行处理响应
3)Ajax原生的用法是比较麻烦的,可以引入一个第三方库,在浏览器进行页面加载的过程中,是可以同时发送多个Ajax请求的,此时这多个Ajax的请求就相当于是并发执行的关系;谁的响应先到,先去处理谁;
1)在Java中,可以使用Maven,从中央仓库里面进行下载,在HTML页面中,可以直接套一个script标签;
1)搜索juery.cdn直接把这段代码粘贴到你的前端代码里面 <script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script> <!-- //基于jquery的Ajax来使用,他里面就一个对象; --> <!-- //Ajax只支持一个大括号对象,大括号对象里面可以有多个值; --> 2)我们搜索jquery.cdn 2.1)我们先在搜索引擎中搜索jQuery.cdn查询词 2.2)在结果中我们寻找一个合适的cdn的url 2.3)我们打开对应的url加载出jquery本体 2.4)创建jquery.js文件,把这些本体来进行粘贴,然后在js代码中进行引入 <script src="jquery.js"></script>或者你直接这么写也是可以的
1)在这里面使用的$其实就是jquery中一个已经定义好的对象,同时$也是JS中最核心的对象,也是一个变量名,jquery中的所有api其实都是$对象中的方法,都是通过$来进行触发的,变量名其实是用数字,字母,下划线所构成的,在一些语言中,也是支持$作为变量名的
2)$.ajax({}),本义上就是说我们想要通过$对象来进行调用ajax函数,参数只有一个,这个参数就叫做一个对象,对象里面通过若干个不同的键值对来表示不同的参数;
3)咱们的ajax本质上是可以支持各种不同的HTTP方法;
2)在JS中,浏览器的页面加载,是可以同时可以发起多个Ajax请求的,这里面的多个Ajax其实上是一种并发执行的关系,例如说回调函数等等;
<script>
$.ajax(
{
type:"GET",//HTTP请求的方法
URL:"https://www.baidu.com",//HTTP请求的url
sucess:function(data,status)
{
//data就是HTTP响应的body,status就是相应的状态码
console.log(data);
console.log(status);
//这里面的success就对应着一个回调函数,这个函数就会在正确的获取到HTTP响应之后来进行
//调用,响应能正确回来就进行调用,响应不回来就不会调用
}
error:function(data,status){
//error也是相当于是一个回调函数,这个函数会在请求失败之后进行触发
//这也体现了异步
console.log("获取响应失败");
}
}
)
</script>
但是当我们使用ajax来向搜狗服务器发送一个HTTP请求的整个过程中,我们通过费德勒抓包已经可以发现搜狗服务器返回了一个200OK,body是text/html,但是为什么浏览器仍然认为这是一个错误的请求呢?
1)出现这个错误的原因是因为出现了浏览器禁止跨域访问,跨域访问就是跨越多个域名或者是跨越多个服务器;
2)当前咱们的页面所处于的服务器是本地文件,页面中ajax请求的URL,域名是www.sougou.com,这样就出发了跨域操作,什么样子不算跨域,当前页面处在的服务器就是在www.sougou.com,页面再通过ajax请求url,域名就是www.sougou.com,这种就不算跨域,你页面当前所在的服务器必须和ajax请求的服务器必须是同一组服务器,不是同一组,就不可以跨域,端口必须也是一样;
3)当然当前也是可以有方法来绕过这个跨域请求,如果说对方的服务器返回的响应中带有响应关的响应头,允许跨域操作,就是可以被浏览器正常的显示的;
十一)通过TCPSocket发送HTTP请求
实现一个HTTP请求Socket是在客户端进行使用,ServerSocket主要是在服务器进行使用
1)socket的含义就是两个应用程序通过一个双向的通信连接实现数据的交换,连接的一段就是一个socket,又称为套接字,实现一个socket连接通信至少需要两个套接字,一个运行在服务端(插孔),一个运行在客户端(插头);
2)套接字用于描述IP地址和端口,是一个通信链的句柄,应用程序通过套接字向网络发出请求或应答网络请求,注意的是套接字既不是程序也不是协议,只是操作系统提供给通信层的一组抽象API接口;
发送请求:拼接字符串,接收响应:解析字符串
所谓的发送HTTP请求,本质上就是按照HTTP的格式向TCP Socket里面写入一个字符串
所谓的接收HTTP响应,本质上就是从TCP Socket中读取一个字符串,再按照HTTP的格式进行解析
可以基于Socket的知识,完全可以构造出一个简单的HTTP客户端程序,来进行发送各种类型的HTTP请求
咱们的JAVA来进行构造一个HTTP请求,其实主要就是基于TCPSocket,按照HTTP请求的报文格式,构建出一个匹配的字符串,然后再写入到Socket里面即可
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintStream; import java.net.Socket; import java.util.Scanner; public class HTTP { int serverport; String serverIP; Socket socket=null; //我们构建HTTP请求发送给服务器的时候,就要知道咱们这个请求向哪里进行发送 还要知道我们发送目标服务器的IP地址和我们要发送到哪一个目标程序上面 所以我们就必须要知道服务器的相关信息 public HTTP(String serverIP,int Serverport) throws IOException { this.serverIP=serverIP; this.serverport=serverport; this.socket=new Socket(serverIP,serverport); } public String get(String url)throws IOException { StringBuilder request=new StringBuilder(); //构造首行 request.append("GET "+url+" HTTP/1.1\n"); //构造header request.append("Host "+serverIP+":"+serverport+"\n"); //构造空行 request.append("\n"); //GET请求不需要正文部分,所以到这里构造就结束了 System.out.println(request); OutputStream outputStream= socket.getOutputStream(); InputStream inputStream=socket.getInputStream(); //因为outputstream是一个字节流,以字节为单位进行写入 因此需要把Stringbulider转化成字节数组 outputStream.write(request.toString().getBytes()); 这个该过程就相当于向服务器发送了一个GET请求 //读取响应,先创建一个缓冲区 byte[] buffer=new byte[4096]; //它的返回值是读取到的字节数; int n=inputStream.read(buffer); return new String(buffer,0,n,"utf-8");//这就表示我们返回响应数据的有效响应范围 } //具体的实现方法和钢材的一样,就是多了body这个字符串 public String post(String url,String body)throws IOException { StringBuilder request=new StringBuilder(); //构造首行 request.append("POST "+url+" http/1.1\n"); //构造header request.append("Host: "+serverIP+":"+serverport+"\n"); request.append("Content-type: text/plain\n"); request.append("Content-Length: "+body.getBytes().length+"\n");//POST请求的参数不是字符的个数,而是字节的个数 //构造空行 request.append("\n"); //构造body request.append(body); //发送请求: OutputStream outputStream= socket.getOutputStream(); outputStream.write(request.toString().getBytes()); //准备接受服务器返回的数据 byte[] arr1=new byte[4096];//我们要先准备好我们的接收缓冲区 InputStream inputStream=socket.getInputStream(); //将服务器返回的数据填充到我们的缓冲区里面 int length=inputStream.read(arr1); return new String(arr1,0,length); } public static void main(String[] args){ //1.验证GET请求是否正确 HTTP http=new Http(); String str=http.get("127.0.0.1:8080/Java100",8080); System.out.println("响应数据是"+str); //2.验证POST请求是否正确 String str1=http.get(url,port); System.out.println(str1+"是POST请求返回响应的数据"); } }
HTTP使用明文传输,内容可以被窃听;
1)由于通过网络传输的任何的数据包都会经过运营商的网络设备,比如说路由器和交换机,那么运营商的网络设备就可以进行解析出你传输的数据内容,并进行篡改;
2)当进行点击下载按钮就是相当于是再给服务器发送了一个HTTP请求,获取到的HTTP响应其实就包含了下载链接,运营商劫持之后,发现这个请求时要进行下载天天动听,于是就会自动会把用户的响应给进行替换成QQ浏览器的下载地址了;
十一)什么是HTTPS?
HTTP:HyperText Transport Protocol
1)使用明文传输,内容可以被窃听
2)不验证通讯方的双方身份,很可能会遭受到中间人攻击
3)无法验证报文的完整性,很容易被篡改;
HTTPS就是在HTTP协议的基础上引入了一个加密层,本质上是套上了一层TLS/SSL协议,正常情况下HTTP协议都是按照文本的格式明文传输,这是就有可能发生流量劫持,因为从源主机客户端发送的主机到目标主机服务器进程所在的主机要经过很多的网络设备,例如路由器和交换机,这些路由器和交换机甚至可以做到一些应用层级别的解析,例如URL网址是a,就偷偷的改成b,通过inferer知道上一个页面,就偷偷插入一个小广告啥的;
HTTPS:HTTP+加密+认证+完整性保护,
HTTPS通过数字证书解决了中间人攻击的问题,使用加密手段解决了明文通讯和数据完整性的问题,对称加密和非对称机密都是包含在SSL里面的,所以说SSL不仅仅是应用于HTTPS,很多地方都是可以用到SSL的;
在SSL里面我们涉及到的加密操作,本质上就分为两种:
1)对称加密
2)非对称加密
相关概念: 明文:真正要传输的原始信息 密文:加密之后的信息,即使这个密文被别人获取,别人也看不懂 密钥:可以给予一个密钥,一般是一个字符串,将一个数据(文本或二进制数据),密钥一般是字符串,进行加密,是有相同的密钥就可以进行解密,通过秘钥我们可以把明文转化成密文,或者把密文转化成明文 加密:将明文通过加密手段,转化成密文; 解密:将密文通过解秘手段,转化成明文; 对称加密:加密和解密使用同一个密钥; 非对称加密:加密和解密使用不同的密钥 公钥和私钥的关系: 通过公钥来进行一定的算法可以生成私钥; 对称加密,成本是比较低的,速度也是极快的; 非对称加密,成本是比较高的,速度也比较慢;
咱们的孙红雷曾经拍过一个电影叫做毒战,孙红雷是缉毒警察,获取到情报,咱们的A和B两方犯罪团伙要进行DP交易
咱们的孙红雷先和A进行接头,自己扮演B
然后再和B进行接头,自己扮演A,从而掌握了关键证据,把两伙人都给干掉
客户端和服务器就相当于是A和B
1)对称加密:加密的时候,通过密钥A把明文加密成密文来进行传输,解密的时候,也通过密钥A来把密文还原成原文;
2)非对称加密:加密的时候,通过密钥1把明文变成密文,解密的时候,通过密钥2把密文变成明文;
3)密钥1和密钥2是不同的密钥,虽然这两个密钥不同,但是他们是存在关联关系的,他们是进行成对出现的
4)非对称加密的公钥和私钥是成对出现的,可以使用密钥1进行加密,密钥2进行解密,也可以使用密钥2进行加密,密钥1进行解密;
5)通常会把一个密钥给公开出去,别人就可以使用这个密钥来加密了,自己则会留下一个密钥进行解密,这时我们就可以把公开出去的密钥叫做公钥,把自己保留的密钥称为私钥,两个密钥,谁进行公开出去时都可以的;
6)A通过公钥把信息进行加密,只是加密,别人知道了这个公钥,也是不能进行解密的,只有知道私钥的人才可以进行解密,同时这个私钥也可以更开出去作为公钥,刚才的公钥自己作为私钥,总而言之要么通过公钥加密,私钥解密;要么通过私钥加密,公钥解密;
0)咱们的服务器在最开始上线的时候,就需要向咱们的第三方公信机构这里面申请一个证书,这个服务器要提供一些相关的资质,咱们的服务器就会给这个客户端一个合法的证书,咱们的这个证书里面就包含了服务器生成的非对称加密的公钥,证书就是一段特殊含义的数据;
1)客户端向服务器端索要证书,服务器在收到客户端的索要证书的请求之后,会生成一个非对称加密的公钥public1,私钥private1,开出去的公钥是用来加密对称加密的密钥;
2)服务器会使用非对称加密返回一个数字证书,证书里面包含了服务器所公开出去public1;
如果说此时黑客想要生成一个public2返回给客户端是不可能的;
3)客户端对服务器发过来的证书进行检验,客户端就拿着这个证书到第三方机构进行检验;
4)证书检测合法,说明此时服务器传过来的public1是靠谱的,那么此时客户端生成一个对称密钥HH,获得证书里面,使用公钥public1对对称密钥HH进行加密,发送给服务器;
4)服务器收到这个请求之后,使用私钥private1进行解密,得到对称加密中的对称密钥HH;
5)客户端发出的后续的请求,后续的请求都是通过这个对称密钥HH进行加密的,收到的数据也是通过这个对称密钥HH进行解密的;
引入对称加密,来进行加密业务数据
引入非对称加密,来加密对称密钥
引入证书,来向客户端证实当前的公钥是真实可信的,搞不好会伪造证书
6)校验证书不通过浏览器会有错误提示,提示该网站证书非法,继续访问存在安全风险,但是还有一个按钮,继续访问;
1)如何校验证书?
1)注意整个证书上面其实也是有一些校验机制,比如说咱们的身份证,身份证的布局,照片,背面都需要带国徽;
2)还可以向工信机构进行求证;
如果说黑客进行伪造了证书,那么此时就会露馅,于是浏览器就会弹窗警告;
2)如何解决中间人攻击?
解觉方案:关键要点就是说我们必须要让我们的客户端进行确认,当前的公钥确实是来自于服务器,而不是由黑客来进行伪造的;就类似于孙红雷那一步电视剧,交易双方就需要验证到底孙红雷是卧底还是交易方的大佬;
3)如何验证报文的完整性?
使用加密的方式也间接的保证了数据的完整性问题,如果是不完整的数据或有多余的数据,那么在解密时会报错,这样就能间接的保证数据的完整性了;
关于证书:
1)那么此时就可以通过证书,把公钥要放在里面,当客户端想要这个公钥的时候,就不仅仅只是索要这个公钥,这时就是索要一个证书,公钥就在这个证书里面;
2)这个证书不是服务器自己生成的,而是要经过第三方的认证才可以,所以当客户端拿到证书之后,就会到第三方的机构进行认证,来检测证书是否合法,证书如果合法,就可以信任其中的公钥了(公钥是证书中的一些字段);
3)服务器开发者会在开发服务器的时候就要去第三方机构进行认证,来获取证书;
4)黑客是不可以伪造证书的,证书上有着一些重要信息;
HTTPS在HTTP的基础上引入了加密层,是基于SSL/TSL来进行的加密
1)引入对称加密,来进行加密业务数据
2)引入非对称加密,来进行加密对称秘钥
3)引入证书和第三方公信机构,来证明服务器传输过来的公钥是合法的
这一个整个的加密过程,与其说是为了防止数据被拦截,倒不如是说防止数据被篡改
2)既然我们的HTTP数据已经经过了加密,那么为什么Fidder仍然可以抓到并解析HTTPS中的数据包呢?
1)Fidder之所以可以进行抓包,是因为咱们在进行第一次启用HTTPS功能的时候,弹出的那一个对话框是密切相关的,所以我们说一定要点击是;
2)这里面的是操作,其实本质上就是让咱们的操作系统能够信任Fiddler提供的证书,相当于是给Fidder授权了,允许Fiddler进行中间人攻击;
中间人攻击的过程:
1)服务器和Fiddler都会向第三方机构申请一个合法的证书,服务器生成了一对公钥和私钥(public1和private1),Fiddler也会生成一对公钥和私钥(public2,private2);
2)客户端向服务器发送一个HTTPS请求,向服务器索要证书;
3)于是咱们的服务器就会向客户端返回一个证书,里面包含着public1,这个服务器的证书会被Fiddler所截获,同时Fiddler会保存这个服务器的证书和服务器的公钥,同时Fiddler会向客户端返回自己的证书,这个证书里面包含着Fiddler的公钥;
4)客户端会拿着这个Fiddler传递的证书到第三方机构去进行校验,因为最开始安装Fiddler的时候咱们已经选择信任了这个证书,所以我们的浏览器看到这个Fiddler的证书,就不会再次选择报警了,如果说你是一个黑客,你进行伪造了一个你自己并不会信任的证书,此时浏览器就会弹出一个框,显示说这是一个不安全的链接
中间人攻击的过程:
客户端 黑客 服务器
1)首先客户端向服务器索要非对称加密的公钥 此时已经入侵了电脑 此时服务器自己生成了一对公钥和私钥,public1,private1;2)服务器在收到客户端的请求之后向客户端返回自己的公钥public1,但是此时黑客截取到了这个信息,知道了服务器的公钥,同时生成自己的公钥和私钥,public2,private2,此时黑客就会向客户端返回自己的公钥public2,本来是客户端应该接受服务器的public1,但是此时黑客进行了入侵,返回的是自己的黑客的public2;
3)此时的客户端就会拿着这个public2来对对称加密的密钥进行加密,得到了一个密文,到了黑客这里拿private2进行解密,然后得到对称加密的密钥,但是此时黑客为了隐藏自己的身份,再根据一开始得到的public1,也就是说黑客把服务器这里面的真正的公钥public1,对对称密钥进行加密,得到了另一个密文,传输给服务器,然后服务器在来进行使用private1进行解密拿到对称加密的秘钥;
因为服务器要把自己的公钥返回给客户端,这就有可能会受到中间人攻击问题
中间人攻击的关键:是因为咱们的黑客也自己生成了一份公钥和私钥,黑客会拦截服务器给客户端返回的非对称加密的公钥,用自己生成的公钥进行替换,HTTPS 通过数字证书解决了中间人攻击的问题;
那么既然都有非对称加密了,那么为什么还要使用对称加密呢?
因为咱们的对称加密的计算开销是远远小于非对称加密的,也就是说对称加密算的快,非对称加密算的慢,因为你的非对称加密传输的是秘钥,传输的数据量也不大,传输的次数只有一次,如果我们针对业务数据进行非对称加密,成本就会变得非常大;
1)因为对称加密,成本是比较低的,机器资源消耗是比较少的,速度也是非常快的,(数据量多的可用对称加密)
2)但是非对称加密,成本高,机器资源消耗高,速度比较慢;