目录
编辑一、HTTP 协议是什么
二、抓包工具的使用
三、HTTP 请求
1、认识 URL
2、认识方法
3、认识请求 “报头”
HOST :
Content-Length 和 Content-Type编辑
User-Agent
Referer
Cookie
四、HTTP 响应
1、认识状态码
2、通过 form 表单构造 HTTP 请求
3、通过 ajax 构造 HTTP 请求
4、使用第三方工具构造 HTTP 请求
五、HTTPS
1、认识HTTPS
2、加密
3、证书
一、HTTP 协议是什么
HTTP 属于是应用层最广泛使用的协议之一
浏览器获取到网页就是基于 HTTP
所以我们可以认为:HTTP 就是 浏览器 和 服务器 之间的交互桥梁
当我们在浏览器中搜索网址的时候,这个东西更准确的说,叫做 URL
浏览器就会根据这个 URL ,构造出一个 HTTP 请求,发送给服务器,服务器就会返回一个 HTTP 响应(包含了 html ,css ,js,图片)
浏览器再把得到的 html 数据进行显示出来(渲染)
二、抓包工具的使用
HTTP 协议的交互详细过程,是可以借助第三方的工具来看到的,称为 “抓包” 工具
抓包工具有很多,我这里使用的是 fiddler
当我们打开 fiddler 之后,它就会立即显示出当前电脑上某个程序使用 http 和服务器交互的过程
fiddle 本质上是一个代理程序,使用的时候有两个注意事项:
1、可能和别的代理程序冲突,使用的时候要关闭其它的代理程序(包括一些浏览器插件)
2、要想正确抓包,还需开启 https 功能
代理分两种:正向代理和反向代理
代表客户端的代理叫做正向代理
代表服务器的代理叫做反向代理
https 是基于 http 搞出来的进化版协议
当下互联网上绝大部分的服务器都是 https ,fiddler 默认不能抓 https 的包,需要我们手动启用一下 https 并安装证书
把这几个复选框都给勾上, fiddler 才能抓取 https ,首次勾选的时候,会弹出一个对话框,问你是否要安装对应的证书(英文) ,这个时候要选择 “是”
当我们再重新打开一个页面的时候,就可以看到产生的 http 请求
浏览器打开一个页面,对应的 HTTP 请求可能是一个,也可能是多个
其中,这个就是我们最关注的一条,再请求 百度 的首页页面的时候,其它的请求都是基于这个请求产生的(百度主页里,其他代码又产生了别的请求)
双击左侧请求列表中的选项,就能看到请求中的详细情况
http 请求,是有一定的格式的,fiddler 会按照格式解析,呈现出不同的显示效果,此处就看最原始的效果(raw)
观察抓包结果,可以看到,当前 http 请求,其实是个 行文本 格式的数据
行文本 的格式,相比于 tcp 这种二进制格式来说,就更方便用户直接观察
响应数据本来也是文本的,但是有的服务器会对响应进行压缩(变成二进制了),压缩式为了节省带宽
有了以上的认知之后,我们就可以来了解一下 http 里面一些关键信息的含义了
三、HTTP 请求
我们点开响应内容:
首行,包括三个部分,之间使用 空格 来区分
GET : HTTP 的方法(method)
URL :俗称的网址,叫做唯一资源定位符
HTTP/1.1 :版本号
URL 叫做唯一资源定位符,标识互联网上的唯一的资源的位置,描述资源在哪(在哪个服务器的哪个目录下的哪个文件中)
还有一个 和 URL 名字类似的东西:
URI:唯一资源标识符(身份标识,为了和别的资源分别开)
实际上,URL 也可以起到身份标识的效果,URL 也可以视为是一个 URI
1、认识 URL
先来看一下 URL 的协议格式:
URL 的协议格式,是由 rfc 系列文档定义的
tcp ,ip ,udp 协议格式都是 rfc 系列文档定义的
URL 不是 http 专属的,很多协议都可以使用 URL
URL 的最关键的四个部分:
1、域名 / IP 地址
2、端口号
3、带层次的路径
4、查询字符串(以键值对的方式来组织的)
一个 URL ,这里的几个部分,有些是可以省略的!!!
比如这个,省略了端口,省略端口的时候,浏览器会提供默认端口
对于 http 来说,默认端口是 80,对于 https 来说,默认端口是 443
/ 也是路径,没有省略,只是有点短,代表 “根目录”
这里的 “根目录” 指的是 HTTP 服务器的根目录
HTTP 服务器是系统上的一个进程,就委托这个服务管理系统上的一个特定的目录,这个目录里的资源都可以让外面去访问
HTTP 协议 和 HTTP 服务器 之间是什么关系?
一个 HTTP 服务器 提供的资源是很多的,不同的路径,拿到的是不同的服务器
但是正常情况下,是这个样子的:
这个 URL 里,就带有 query string
query string 是以 ?开头,以键值对的方式组织,键值对之间使用 & 分割,键和值之间使用 = 分割
URL 里面有些字符是有特定含义的,所以就需要对内容进行重新编码(urlencode),如果不编码,直接写中文,浏览器可能就没办法正确识别了
2、认识方法
方法描述了这次请求的语义(想干什么)
实际开发中,这里的方法大部分都是用不到的,最常见的就是两个:GET ,POST
此处看到的 HTTP 的方法的语义,是 HTTP 设计者的美好的想法,但是实际上,开发的时候,语义仅供参考
触发 GET 请求的方式:
1、在浏览器的地址栏里直接输入 URL
2、html 里的 link ,script,img,a....
3、通过 js 来构造 GET 请求
第一行,称为 “首行”,剩下来的被圈起来的部分叫做 “header” 部分
POST 典型的就是登录
登录跳转的时候会涉及到 POST,另一种典型情况就是上传文件
当然也有其它触发 POST 请求的情况,但是这两种更为典型
HTTP 请求可以分成是四个部分:
1、首行
2、请求头(header)
3、空行
4、正文(body)
如果是 GET 请求,没有 body
如果是 POST 请求,一般有 body
在抓包结果中,我们可以看到,post 的结果是程序员自定义的内容
其中,uuid 指唯一身份标识:可以通过一定的算法,构造出这样的一个长字符串,每次构造的长字符串都是不同的
这里存放的数据的内容和格式,都是程序员自主定义的
GET 和 POST 之间的典型区别:
(1)GET 也可以给服务器传递一些信息,只不过 GET 传递的信息一般都是放在query string ;而POST 传递信息则是通过 body
(2)GET 请求一般是用于从服务器获取数据,POST 一般是用于从服务器提交数据(语义上的差别)
(3)GET 通常会被设计成幂等的,而 POST 不要求幂等
(4)GET 可以被缓存;而POST 一般不能被缓存
注意:这里的区别只是一个习惯用法,GET 也不是不能有 body ,POST 也不是不能有 query string,只是非常少见
GET 和 POST 其实没有本质区别(在大部分场景下,彼此之间都能够互相替代)
但是在使用习惯上,还是有差异的
幂等可以理解成:相同的输入,得到的结果也是相同的
缓存指的是:把请求的结果保存下来了,下次请求就不必真请求了,直接取缓存结果了
所以,缓存的前提是幂等
3、认识请求 “报头”
下列部分,就是 header 部分,这里是一堆键值对!
每一行,是一个键值对,每一个键值对之间用 ; 分割
这些键值对都是 HTTP 事先定义好的,有特定含义的
比如:
HOST :
大概描述了服务器大概所在的地址和端口
HOST 这里的 地址 和 端口,用来描述你最终要访问的目标
也就是说,这里的内容,大概率和 URL 中是一样的 ,也有不一样的情况
Content-Length 和 Content-Type
Content-Length :表示 body 中数据的长度
Content-Type :表示请求的 body 中数据的格式
如果是 GET 请求,没有 body,请求中没有这两个字段
如果是 POST 请求,有 body,请求中必须有这两个字段
User-Agent
主要描述了当前 浏览器 和 操作系统 的版本
最早期的浏览器,只支持文本,后来支持图片,再后来支持视频,音频.....
网站开发者在开发的时候,做的网页是否要带图片,视频之类的,就很难抉择
于是干脆分成了多个版本,针对不同的浏览器做多个版本,判定请求的 user-agent,根据这个不同的类别,返回不同的版本内容
现在,User-Agent 主要用来区分 PC 和 移动
Referer
表示当前页面的 “来源”
如果直接通过地址栏输入地址,直接点击收藏夹....都是没有 referer
我们浏览网页的时候,会发现网页上常常会有广告,广告主按照广告的点击量给广告平台发钱,广告被点击了多少次?次数如何衡量?这些次数是由广告商和广告平台一起统计的,如果统计的数据对上了,那么就没有问题,如果数据没有对上,那么程序员就要去查问题的原因
但是一个广告也可能被投放在了多个平台上,那么就是用 referer 来分辨广告是在哪个网页上被点击的
HTTP 本身是明文传输,意味着很容易能够获取到请求内容,也有办法篡改内容
那么有没有可能本来是来自搜狗的请求,但是 referer 被改成了别人的呢?
referer 是 HTTP 层面的东西,交换机和路由器正常情况下,是不会干涉的,但是有时候运营商为了钱,可能会出现篡改数据的情况
Cookie
Cookie 是一个非常重要的 header 属性
本质上是 浏览器 给 网页 提供的 本地存储数据 的机制
网页,默认是不允许访问你计算机的硬盘的(安全)
Cookie 就相当于是 浏览器对于访问硬盘做出了明确的限制
Cookie 就是通过键值对的方式来组织数据的
至于 Cookie 中具体存的内容是什么,也就是程序员自定义的部分
Cookie 是从哪来的?
Cookie 中的数据,是来自于服务器的
服务器会通过 HTTP 响应的报头部分(Set-Cookie字段)
服务器来决定,浏览器的 Cookie 要存什么
Cookie是存在哪的?
可以认为是存在于浏览器中,存在于硬盘的
Cookie 在存的时候,是按照 浏览器 + 域名 维度来进行细分的
不同的浏览器,各自存各自的Cookie
同一个浏览器,不同的域名,对应不同的Cookie
Cookie 里面的内容,不光是键值对,同时还有过期时间
Cookie 要到哪里去?
回到服务器去
客户端同一时间是有很多的
客户端这边就会通过 Cookie 来保存当前用户使用的中间状态,当客户端访问浏览器的时候,就会自动的把 Cookie 的内容带入到请求中,服务器就知道现在客户端时什么样的了
四、HTTP 响应
1、认识状态码
响应也是由四个部分构成:
1、首行
2、header
3、空白行,表示 header 的结束标记
4、body
HTTP 的状态码,描述了这次响应的结果
200 :OK成功了
404 : Not Found,访问的资源不存在
403 : Forbidden ,访问被拒绝(没有权限)
302:Move Temporanly 重定向(类似呼叫转移)
500:服务器内部错误(服务器代码抛异常)
504 : getway timeout(响应时间太久)
重定向和请求转发的区别:
重定向:
请求转发:
重定向,可以重定向到外部资源(跳转到别的网站)
请求转发只能该服务器内部的资源之间转发,少了一次交互,更高效
这么多的状态码,其实是可以分为几个大类的:
HTTP 协议里面,有不少地方,是可以由程序员自定义的:
1、URL 中的路径
2、URL 中的 query string
3、header 中的键值对
4、header 中的 Cookie 键值对
5、body
HTTP 的报文协议格式
2、通过 form 表单构造 HTTP 请求
对于 GET
1、地址栏直接输入
2、点击收藏夹
3、html 中 的 link ,script,img,a.....
4、通过 form 标签
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><!-- 表单标签,允许用户和服务器之间交互数据 --><!-- 提交的数据以键值对的结构来组织 --><form action="https://www.sogou.com" method="get"><input type="text" name = "studentName"><!-- input type = submit 这时候构造了一个特殊的提交按钮,value 属性描述了按钮中的文本 --><!-- 点击这个按钮就会触发该 form 表单的 “提交操作”,也就是构造 HTTP 请求发给服务器 --><input type="submit" value="提交"></form>
</body>
</html>
我们打开这个网页,然后输入 "zhangsan" 后,在 fiddler 中观察HTTP 的请求
除了首行之外,剩余部分都是浏览器自主添加的
可以看到,我们构造的这个请求,搜狗的服务器没有做什么特殊的处理,仍然是噗噗通通的返回搜狗主页了
我们后续写服务器代码,就可以根据需求,来获取 URL 中的 query string ,从而完成不同的功能
对于 form 构造的 POST 请求来说,body 里面的数据格式,就和 query string 是非常相似的,也是键值对结构,键值对之间通过 & 分割,键和值之间使用 = 分割
form 标签,只能构造 GET 和 POST ,无法构造 PUT ,DELETE 等
3、通过 ajax 构造 HTTP 请求
ajax 也是浏览器提供的一种,通过 js 构造 HTTP 请求的方式
a 指的是 asynchronize,异步的意思
同步:A 始终盯着 B,A 负责关注 B 啥时候就绪
异步:A 不盯着 B,B 就绪后主动通知 A
html 中,通过 ajax 发起 HTTP 请求,就属于是 “异步” 的方式
这一行代码执行 “发送请求” 操作之后,不必等待服务器响应回来,就可以立即先往下执行,当服务器的响应回来了之后,再由浏览器通知到咱们的代码中
代码中如何使用 ajax?
1、js 原生提供的 ajax 的 api,但是原生的 api 很难用
2、jquery 提供的 ajax ,api 针对原生 api 的封装,简单很多
我们这里选择更简单的第二种写法
jquery 中,$ 是一个特殊的全局对象
jquery 的 api 都是以 $ 的方法的形式来引出的
ajax 这个方法的参数,只有一个参数,是一个 js 对象(大括号表示的键值对)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head>
<body><!-- 引入 jquery --><script src = "https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.js"></script><script>$.ajax({type :'get',url:'https://www.sogou.com?studentName=zhangsan',// 此处 sunccess 就声明了一个回调函数,就会在服务器响应返回到浏览器的时候触发该回调//正式此处的回调,体现了异步success:function(data){//data 则是响应的正文部分console.log("当服务器返回的响应到达浏览器之后,浏览器触发该回调,通知到我们的代码中");}});console.log("浏览器立即往下执行后续代码");</script>
</body>
</html>
注意:该代码直接执行,只是能看到构造的请求,无法获取到正确的响应
因为发送请求给搜狗服务器,人家的服务器没有处理我们的请求
请求构造的顺序是从上到下的,但是收到响应的顺序/触发回调的顺序是不确定的(网络上可能会后发先至)
等到后面我们自己编写服务器的时候,就可以给自己的服务器发送请求,自然就能够处理了
和 form 相比,ajax 功能更强
1、支持 put,deelte 等方法
2、ajax 发送的请求可以灵活设置 header
3、ajax 发送的请求的 body 也是可以灵活设置的
4、使用第三方工具构造 HTTP 请求
我们可以使用 postman 进行构造 HTTP 请求
1、先注册登录
2、创建一个 workspace
3、新建一个标签页
除了刚才手动构造之外,postman 还有一个很强的功能:
postman 可以生成构造请求的的代码,方便我们在自己的程序中集成
五、HTTPS
1、认识HTTPS
HTTPS :HTTP + 安全层(SSL)
SSL:用来加密的协议
网络上如果明文传输数据,是非常危险的,需要加密才能保证安全
HTTPS 其实主要涉及到的是其中的 SSL 部分
SSL 并非仅仅是在 HTTPS 中使用
2、加密
进行安全传输的核心就是加密
加密其中一种最简单有效的办法叫做 “对称加密”
a(明文) + key => b(密文)——加密的过程
b(密文) + key => a(明文)——解密的过程
同一个密钥,既可以用来加密,也可以用来解密,就称为对称密钥
对称加密的安全性的前提就是密钥不能被黑客知道
密钥就可以认为是一串 数字 / 字符串
加密的过程,就可以理解为把明文和字符串进行一些列的数学变换(其中最简单的一种方式就是 ^)
由于黑客不知道密钥是什么 ,即使黑客截获了加密的数据,也不知道这里是什么意思
客户端生成密钥还是服务器生成密钥?
由于一个服务器对应很多个客户端,这些客户端每个人都有不同的密钥
假设客户端生成一个密钥,客户端就需要把密钥告知服务器
客户端生成密钥,发给服务器,此时由于密钥刚刚生成,此处的密钥只能明文传输,密钥就可能被黑客给截获了
以上问题,关键在于需要想办法把密钥传递过去,因此还得加密
此处,我们可以引入非对称加密
生成一对密钥:公钥和私钥
明文 + 公钥 => 密文——使用公钥加密
密文 + 私钥 =>明文——使用私钥解密
公钥可以公开,私钥是私藏的
服务器生成一对公钥私钥,其中客户端持有公钥,服务器持有私钥
此时,客户端的公钥从服务器拿,黑客也能知道公钥,但是黑客不知道私钥,因为私钥是服务器自己持有的
客户端使用公钥对对称密钥进行加密,传输给服务器,服务器就可以拿着自己的私钥来解密得到对称密钥
此时客户端服务器就可以使用这个对称密钥进行后续传输了
为什么有了非对称加密,还要继续保留对称加密呢?
对称加密速度快,非对称加密速度慢
使用对称加密是为了尽可能提高整体的速度
3、证书
但是问题来了,有时候黑客会模仿服务器给客户端发送密钥,也就是中间人攻击
中间人攻击的要点在于,客户端不知道响应式来自于真实的服务器还是黑客的
解决中间人问题的关键在于,让客户端能够辨别当前这个响应(公钥)是服务器真实的公钥
于是,我们引入了 “证书”(本质上是引入了第三方的公证机构)
服务器(网站)在设立之初,就需要去专门的认证机构,申请证书(提供一些资质)
审核通过,就会给你颁发证书,服务器生成的公钥也就包含在这个证书中
客户端向服务器请求公钥的时候,就不单单是请求一个公钥,而是把整个证书都请求过去了
客户端拿到证书之后,就可以对证书进行校验(验证一下证书是不是假的,是不是被篡改的)
如果发现证书是无效的,浏览器就会直接弹窗告警
客户端拿到证书,就可以对证书进行一个校验
证书上面会带有一个特定的字段,叫做证书的签名,客户端可以通过证书的签名看它是不是有效的证书
签名就是一个被加密的字符串
客户端就可以使用认证机构提供的公钥进行解密,解密之后得到的结果,相当于是一个 hash 值
类似于 tcp 和 udp 里面的校验和,根据证书的其它字段,综合计算出来的结果
客户端就可以使用同样的 hash 算法,针对其它的字段再计算一次 hash值,得到 hash2
看看 hash1(从签名中解出来的)和 hash2(客户端自己算的),如果这两个值相同,就说明证书是有效的(没有被篡改过)
黑客能否把证书给篡改了?
一旦替换了公钥,意味着客户端算的 hash2 和签名解密出阿里的 hash1 就对不上了,客户端就知道无效
另一方面,黑客不知道认证机构的私钥,即使黑客自己算好了新的篡改之后的 hash 值,也无法加密生成签名
认证机构也有一组公钥和私钥,私钥用来加密 hash 值 得到签名,公钥是客户端拥有的使用公钥解密签名获取 hash