网络原理(5)——HTTP、HTTPS

1. HTTP

1.1 概念

HTTP 全称 “超文本传输协议”,其不仅能传输文本,还能传输图片、音频、视频等等各种数据

HTTP 诞生于 1991 年,目前已经发展为最主流使用的一种应用层协议(没有之一)

目前互联网上见到的 HTTP 协议绝大部分都是 HTTP/1.0 版本,因为 1.0 版本足够好用了,没必要增加成本(浏览器/服务器的兼容性)去升级 2.0 / 3.0,升级带来的收益有限

http 协议是一种典型的 “一问一答” 型协议(客户端发一个请求,服务器返回一个请求,一一对应,如:打开网页就属于典型的“一问一答”)

tip:

一问多答:下载一个大文件

多问一答:上传一个大文件

多问多答:远程桌面(远程控制)

1.2 HTTP 报文格式

借助抓包工具可以观察到 HTTP 请求/响应 的详细情况

TCP/UDP 也是可以抓包的,但日常开发很少会抓 TCP/UDP 层次的包,通常是抓 HTTP 的包

抓包:把通过网卡上的数据获取到,并且解析显示出来

tip:代理

抓包程序,就是一种代理(vpn 类软件,也是代理)

代理又分为正向代理和反向代理,如下图:

1.3 HTTP 抓包

抓包工具

1) wireshark:功能非常强,可以抓 TCP、UDP、IP、HTTP,但是其太繁复了,不利于初学者

2) chrome / edge 开发者工具:在网页中按 F12 即可唤起,自带抓包,很好用,但是没法看到 HTTP 的原始报文数据,不利于初学者


3) fiddler(经典的,功能强大的抓包工具)

官网:https://www.telerik.com/fiddler

使用免费的即可


使用前设置:

1. 确保电脑上退出了其他的代理类软件

fiddler 也是代理,可能会和其他代理冲突,导致不能正常抓包

2. 由于当前网络上大部分网站都是 HTTPS,需要开启 fiddler 的 HTTPS 功能(一次性操作)

在这期间可能会弹出一个对话框询问是否要安装证书(英文提示),一定要选择 yes,若选择了 no,则只能卸载重装


fiddler 的用法

只要启动 fiddler,抓包工作就自动开始了

左侧是抓到的 HTTP 数据包的列表

点击某一项,右侧就能看到请求和响应的详细情况

右上方是请求的详情

右下方是响应的详情

使用记事本的方式查看

当打开响应的时候,看到的是二进制(本身响应也是文本,此处的二进制是压缩后的)

tip:压缩

如:rar、zip 等等,在二进制的角度上对数据进行重新编码,保证信息量不变,体积缩小

体积小了,传输时消耗的带宽就低了,带宽是互联网中最贵的硬件资源,比 cpu、内存都贵

压缩就是用 cpu 资源换带宽资源

此时仅需点击如下,即可解压缩

搜狗主页中返回的响应数据解压缩之后,其实就是主页的 HTML,很多网站皆是如此

浏览器看到的网页就是由 HTML、CSS、JavaScript 构成的,返回一个 HTML 给浏览器就是 HTTP 非常典型的场景

row 标签页就是 HTTP 的原始数据

发送 HTTP 请求,就是往 TCP socket 中按照上述格式写入一段字符串

收到 HTTP 响应,就是从 TCP socket 中读出一段字符串再进行解析

1.4 HTTP 请求响应的基本格式(重要

HTTP 请求/响应 的行文本格式的协议

请求:

1) 首行

2) 请求头(header)

从第二行开始的若干行,一直到空行结束

不知道有多少行,只要遇到空行就结束,每一行都是一个键值对,键和值之间使用 :空格 分隔

HTTP 里请求头中的键值对有哪些,都是 HTTP 标准规定的,不同的请求头都有特定的含义,但是标准里也允许用户自定义一些请求头

3) 空行

请求头的结束标记

4) 正文(body)

有的请求中有 body,有的没有


响应:

1) 首行(首行的三个部分之间用空格分隔,请求也是如此)

2) 响应头

每一行是一个键值对,不确定几行,以空行结尾,键和值之间使用 :空格 分隔

键值对也是标准规定的,有的键值对只能出现在请求中,有的只能出现在响应中,有的都能出现

3) 空行

4) 正文

对于响应来说,正文通常是 HTML/CSS/JSON/图片/音频/字体(体现了服务器给浏览器返回的数据)

2. HTTP 请求(Request)

2.1 URL(唯一资源定位符)基本格式

网络上资源非常多(资源可以是一个网页,一个文件,一个图片...),必须有一套规则,能够找到某个指定的资源,这既是 URL

URI(唯一资源标识符)

可以简单的理解成 URL 是 URI 的一种实现,实际上日常开发中,一般不会刻意区分 URL 和 URI

URL 不是 HTTP 专属的,很多协议都会用到,就像 jdbc 中的 dataSource,设置 url、用户名、密码

jdbc:mysql://127.0.0.1:3306/javaCode?characterEncoding=utf8&useSSL=false

其中 127.0.0.1 为环回 IP,3306 为端口号,若是不写端口号的话,浏览器会自动拼接上一个端口(不是随机分配空闲端口,描述的是服务器的端口,固定的)

端口号如果不写,是根据协议类型来划分的

如果是 http 协议,则浏览器自动加上 80 端口

如果是 https 协议,则浏览器自动加上 443 端口

tip:

1) 键值对之间使用 & 分隔;键和值之间使用 = 分隔

2) 对于一个 URL 来说,主要关心其中的四个部分:

1. IP 地址(域名)

2. 端口号

3. 层次的路径

4. 查询字符串

2.2 url encode

query string 键值对结构中,值可以包含各种内容,万一值里面包含了一些特殊符号,可能会使 url 的解析出现问题(url 中有些符号具有特殊含义,如 :   /   @   ?   &   = 等等)

url encode 本质上就是 “转义字符”,使用一系列特殊的规则,将特殊字符给替换掉

例:在浏览器搜索 C++

转义规则:把要转的字符/汉字,每个字节以 十六进制 的方式表示出来,给每个字节前面都加上 % 就可以了


在浏览器搜索 “跑步”

日常开发的时候,大多数情况下不需要手动处理转码,因为日常使用的一些库(无论前端、后端)都是自带了 url encode / decode 的功能的

2.3 HTTP 的方法

这些方法的使用频率一句话概括:天下 HTTP 方法有十斗,DET 独占八斗,POST 占一斗,剩下的共分一斗

1) GET 方法

a) 直接在浏览器中输入一个 url,就会触发 GET 请求

b) HTML 页面中的很多元素会进一步触发 GET 请求

下面通过打开搜狗搜索示例:

造成这两种刷新请求不同的原因:

1) 当前看到的这些请求是由搜狗主页 html 进一步触发的

html 包含的一些 link、script、a、img...都可能进一步触发 HTTP get 请求。进一步从服务器获取资源(访问一个网页不是一次 HTTP 请求就能搞定的,而是多个 HTTP 请求(尤其是 GET)得到的结果最终汇总而成的)

2)上述请求得到的内容,主要是一些 css 文件、JavaScript 文件、图片文件、字体文件...等(这些内容一般是固定的,改变频率非常低)

当第一次访问搜狗主页的时候,把上述固定的资源都保存下来(保存到电脑硬盘上),后续再访问搜狗,就没必要重复获取上述内容了(重复获取到的东西是一样的),这种机制(浏览器缓存),节省了服务器的带宽,加快了页面展示速度

当使用 Ctrl + F5 刷新网页时,就会忽略缓存,强制从服务器重新读取数据


2) POST 请求的场景

a) 登录/注册

以登录 Gitee 为例:

b) 上传文件

这里的 body 中的内容就是头像图片的二进制内容(base64 转码后的内容)

图片本身是二进制的,HTTP 虽然也能传输二进制,但是很多时候也会把二进制数据进行转码(不一定用 url encode(用它转码后体积太大了),还有一种转码方式 base64 编码(另一种把二进制转成文本的方式))


3) GET 和 POST 的区别

结论:没有本质区别,GET 能用的场景,换成 POST 也可以;POST 能用的场景,GET 也不是不行

但在使用习惯上还是有一些区别:

a) 语义不同,方法表示的含义不同

GET 表示从服务器拿数据;POST 表示往服务器提交数据

虽然可以使用 GET 提交数据,也可以使用 POST 获取数据,没有硬性要求,但是不建议这样做

b) 传递数据的方式不同

GET 传递数据通常是通过 query string(查询字符串) 把自定义数据交给服务器;POST 传递数据,通常通过 body(正文) 把自定义数据交给服务器

给 GET 也能加 body,给 POST 也能加 query string),但一般不会这么做,甚至有些库都不支持解析 GET 的 body,有的产品为了设计简单一致,全都使用 POST

c) GET 方法对应的请求,通常设计成 “幂等” 的;POST 方法对应的请求,对于 “幂等性” 则无要求(这是 HTTP 标准文档建议的做法)

这个区别放在今天就不是特别合适了,在实际开发中,幂不幂等更多是看业务要求,和方法关系不大

幂等性的要求,对于数据的准确性要求高的场景都是非常关键的(比如:支付场景)

tip:

GET 如果设计成幂等的,此时 GET 的结果是可以被缓存的(不仅仅是浏览器,运营商 CDN,运营商的反向代理,服务器里的一些缓存...);POST 不设计成幂等的,POST就不应该被缓存


4) 其他方法

  • PUT 与 POST 相似,只是具有幂等特性,一般用于更新
  • DELETE 删除服务器指定资源
  • OPTIONS 返回服务器所支持的请求方法
  • HEAD 类似于 GET,只不过响应体不返回,只返回响应头
  • TRACE 回显服务器端收到的请求,测试的时候会用到这个
  • CONNECT 预留,暂无使用

日常进行 web 开发时,有一种设计服务器接口的风格,称为 “Restful”(类似于“推荐做法”“最佳实践”),其使用不同的方法表示不同的语义,如下:

增 POST

删 DELETE

改 PUT

查 GET

3. 请求报头和响应报头(header)

3.1 键值对

Host:表示服务器主机的地址和端口(这部分信息其实在 URL 中已经有所体现了)

Content-Length:表示 body 中的数据长度,单位是字节,告诉我们这一个 http 数据包到哪里就结束了(HTTP 基于 TCP,TCP 面向字节流,存在粘包问题)

解决粘包问题

1. 指定分隔符:如果一个 HTTP 数据包没有 body,此时空行就相当于分隔符了

2. 指定数据包长度:如果一个 HTTP 数据包没有 body,此时 Content-Length 就描述了 body 的长度

Content-Type:表示 body 中的数据格式,取值是比较固定的

tip:一个请求/响应中,没有 body,也就没有 Content-Length 和 Content-Type;若有 body,则必须有这俩字段


浏览器从服务器上获取上述三种代码的过程:

tip:前后端

4. User-Agent(简称 UA)

表示浏览器/操作系统的属性

作用一:

在 199x 年代,UA 的意义更大,因为当时网络设备的形式参差不齐,所以对于网站的开发人员有很大的挑战,如果网站只支持文字图片,那在用好设备的人眼里就太 low 了,如果网站能够支持复杂多媒体,在用差一点设备的人眼里,压根就无法显示

解决方案就是通过 UA 字段获取到用户浏览器信息和操作系统信息,从而判断当前用户的浏览器版本都支持哪些特性,从而对症开发版本

在今天,浏览器的功能都差不多了,但是上网的设备还是存在差别,比如用 PC 和手机上网,其屏幕尺寸(比例)是截然不同的,对于这种情况仍然可以通过 UA 的方式来切入

tip:针对上述问题,在前端开发圈子里,研究出了 “响应式编程”,在前端代码中(主要是 CSS),能够自动查询出当前屏幕的尺寸,结合尺寸对页面自动进行重新排版


作用二:

UA 还可以用来做数据统计,在日常开发中有一个很重要的环节,就是需要统计很多业务指标

例如搜狗中的广告,一天有多少广告被展示,多少被点击(不仅仅是总数),哪些广告点击率高...

根据统计结果进一步迭代改进产品


5. Referer

描述了当前页面是从哪个页面跳转过来的

Referer 并不是一定有的,如果是直接在地址栏输入 url 或者直接从收藏夹进入,都没有 Referer

6. Cookie

其中键值对的含义都是程序员自定义的

上述这些键值对,看似是从浏览器通过请求发给服务器的,实际上这些数据最初都是从服务器返回给浏览器的,此处看到的这些数据相当于是浏览器本地存储的

Cookie 里面的内容来自于服务器,首次访问某个网站可能是不带 Cookie,在响应中就会有 Set-Cookie 这样的 header 把一些键值对写回到浏览器这边,浏览器后续访问这个网站就会带有 Cookie

为了安全,浏览器禁止网页直接访问用户的硬盘(文件系统),但并没有把路完全封死,其允许网页通过键值对的方式来存储数据(这样的数据本质上也是在硬盘上),具体这样的键值对是如何存储到硬盘上的,是浏览器封装好的,网页本身无法干预


网页中查看 Cookie

保存有 Cookie 的情况:

删除后:

Cookie 是什么:Cookie 是浏览器本地持久化存储数据的一种机制,按照键值对方式存储,键值对的内容都是程序员自定义的,按照域名分别进行存储(每个网站都有自己的 Cookie,相互不影响)

Cookie 从哪里来:服务器返回的响应数据中包含 Set-Cookie 字段

Cookie 到哪里去:后续浏览器访问同一个服务器的时候,就会把之前存储的 Cookie 再带上,从而发送到服务器这边 


Cookie 常用使用场景:使用 Cookie 保存用户的身份信息

对于 HTTP 来说,针对同一个服务器,每次 HTTP 请求,彼此之前都是独立的

但是登录之后:

登录是前一个请求,后续的请求是如何知道我处于登录状态的呢?

tip:

随着互联网的发展,Cookie 也不是唯一一个在浏览器这边存储数据的机制了,也可通过以下两种机制来存储会话 ID

local storage:也是键值对存储

index db:类似于 “表” 这样的数据结构

登录身份信息的验证也不一定都是基于 session 这样的方式来存储的,其他方式例如业界比较流行的 jwt 方式(用户的信息就存储在客户端,但是加密一下)

7. HTTP 响应详解

7.1 状态码(status code)

状态码表示访问一个页面的结果(是访问成功、失败、其他情况...)

常见状态码

200 OK

这是一个最常见的状态码,表示访问成功

抓包抓到的大部分结果都是 200,如下访问搜狗主页


404 Not Found

浏览器访问的资源在服务器上没有找到(url 中的路径表示要找哪个资源)


403 Forbidden(访问被拒绝,没有权限)


405 Method Not Allowed

HTTP 的方法,网站接收 GET 请求,发送一个 POST(自己写服务器就很容易能构造这样的情况)


500 Internal Server Error(服务器内部错误)

服务器代码出 bug,一般代码中排除异常,但是有没有合理的 catch 住,就会出现 500


504 Gateway Timeout

属于服务器方面出问题了,响应没有在规定的时间内返回

tip:

状态码中 2 开头的都是成功

4 开头的都是客户端这边出现问题

5 开头的都是服务器端这边出现问题


302 Found(重定向)

访问 A 网站,自动跳转到 B 网站(就像运营商的呼叫转移服务)

响应中返回 302 这样的状态码,并且在响应头中添加 Location 属性(包含了 B 网站的地址)

状态码小结:

类别原因短语
1XXInformational(信息性状态码)接收的请求正在处理
2XXSuccess(成功状态码)请求正常处理完毕
3XXRedirection(重定向状态码)需要进行附加操作以完成请求
4XXClient Error(客户端错误状态码)服务器无法处理请求
5XXServer Error(服务器错误状态码)服务器处理请求出错

8. 构造 HTTP 请求的方式

1) HTML form 标签

2) JavaScript ajax

3) Java Socket API

...很多其他方式

在业界有很多第三方工具,能够快速方便的构造处 http 请求,如:postman(简单易上手)、apifox(功能强大,复杂,对新手不太友好)


9. HTTPS

HTTPS 也是一个应用层协议,是在 HTTP 协议的基础上引入了一个加密层

HTTP 协议内容都是按照文本的方式明文传输的,这就导致在传输中出现一些被篡改的情况,例如臭名昭著的“运营商劫持”,就算运营商不劫持,还可能有其他黑客劫持

因此,在互联网上进行明文传输是比较危险的事,HTTPS 就是在 HTTP 的基础上进行了加密,进一步的保证用户的信息安全

9.1 加密

概念:

明文:要传输的原始数据

密文:将明文进行加密之后得到一个让别人不能理解的数据

加密:明文 -> 密文

解密:密文 -> 明文

密钥:进行加密和解密的重要数据/辅助工具

9.2 HTTPS 的工作过程

概念:

加密的方式有很多,但整体可以分成两大类:对称加密非对称加密

对称加密:加密和解密使用同一个密钥

非对称加密:一对密钥(从数学角度生成的一对数)

A 和 B

使用 A 加密,就用 B 解密;使用 B 加密,就用 A 解密

公开出来的密钥称为“公钥”;私藏起来的密钥称为“私钥”

HTTPS 从 HTTP 的基础上引入加密机制

1) 引入对称加密

客户端和服务器交互过程中,一个服务器对应着多个客户端,多个客户端必须使用不同的密钥,若是都使用相同密钥,那黑客只要自己搞个客户端就能知道密钥是什么了

因此就要求让每个客户端连上服务器的时候,自己生成一个随机的对称密钥,服务器也得拿到这个密钥,才能解密


2) 传输对称密钥给服务器

按照这样的传输模式,密钥明文传输给服务器,此时黑客就可能截获到这个密钥,后续的加密形同虚设


3) 引入非对称加密

通过非对称加密,对要传输的对称密钥进行加密(非对称加密运算量开销比较大,比较消耗性能)

非对称加密存在的目的不是取代对称加密,而是“辅助”,业务数据仍然是对称加密传输

非对称加密就涉及到一对密钥(公钥和私钥),公钥随便公开,只要私钥保护好就行


4) 中间人攻击

上面流程中存在严重缺陷,黑客的设备可以在客户端面前假扮服务器,在服务器面前加班客户端,演技够好,骗过双方


5) 避免中间人攻击,引入证书机制

上述问题的关键,在于如何能够让客户端识别出拿到的公钥是否正确合理

此处就需要引入第三方公证机构:

当搭建服务器想要使用 HTTPS 时,就需要在公证机构申请证书(电子的,一串数据),申请的时候,需要提交一些材料(如:网站的域名、营业执照、备案号...),公证机构就能生成一个 “电子证书”

服务器申请证书后,后续客户端从服务器拿公钥,就不只拿公钥,而是拿整个证书

此时,客户端就可以凭借证书中的 “数字签名” 对证书的合法性进行验证

原始数据相同,计算得到的校验和就相同,校验和不同,说明原始数据就不同

客户端验证数字签名

1. 客户端把证书中的各个字段再算一次校验和,得到 checksum1

2. 客户端使用公证机构的公钥,对数字签名进行解密,得到 checksum2

3. 对比 checksum1 和 checksum2,若相等,视为当前证书的各个字段和服务器发出的证书相同,就是合法证书;若不相等,意味着证书上的内容被中间的黑客篡改过,此时浏览器往往会弹出警告页面(红色背景),提示用户,该网站不安全

tip:

1) 公证机构的公钥是操作系统内置的,黑客很难下手,因此一般不需要确定其是否正确

2) 理论上来说黑客不可以篡改数据之后,同时更新数字签名,让数字签名解密出来的 checksum2 和篡改过的 checksum1 一致

因为黑客篡改了数据之后,要想重新生成数字签名,需要使用公证机构的私钥来加密,这个私钥不是黑客能拿到的

黑客如果自己生成一个私钥,客户端拿着公证机构的公钥也解密不了,客户端解密出错,也可以认为是证书有问题,浏览器弹出警告窗口


9.3 Fiddler 如何解析 HTTPS 的数据

像 Fiddler 这样的抓包工具,能拿到对称密钥,才能对数据解密

Fiddler 之所以能解析 HTTPS 数据,是因为我们信任了其提供的证书,相当于我们允许了 fiddler 这个中间人对我们进行攻击

浏览器验证 fiddler 的证书

1) 计算证书的各个属性和校验和,checksum1

2) 从数字签名解密(拿着客户端信任的 fiddler 的公钥来解密),得到 checksum2


10. 经典面试题:你在浏览器输入 url 后,到最终展示出页面为止,这个过程中计算机都做了哪些事

基本思路

1) 站在网络原理的角度

  • DNS 解析
  • HTTPS 的握手过程(对称加密、非对称加密、中间人攻击、证书...)
  • HTTP 浏览器构造 HTTP 请求、服务器返回 HTTP 响应(HTTP 都有啥)
  • TCP 三次握手、四次挥手、确认应答、超时重传...
  • IP 如何管理 IP 地址,如何进行数据转发
  • 数据链路层 以太网

2) 站在服务器后端开发的角度

单机架构

  • 服务器如何处理 HTTP 请求(Spring)
  • 根据请求计算响应(业务逻辑)
  • 把响应返回给客户端(Spring)

分布式 / 微服务架构

  • 网关
  • 分发给应用服务器
  • 分发过程涉及到服务发现,负载均衡
  • 应用服务器又涉及到操作数据库、操作 redis、操作mq...
  • 服务器之间通过 rpc 进行相互调用

3) 站在网页前端开发的角度

  • HTTP 请求是怎样在浏览器中构造的
  • 拿到的 HTTP 响应怎样被浏览器解析的
  • 如何对上述过程进一步优化
  • vue 框架...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值