OSI 七层模型
OSI 七层模型
OSI
Open System Interconnection适用于所有网络

七层网络协议模型
- 应用层
- 表示层
- 会话层
- 传输层
- 网络层
- 数据链路层
- 物理层

不同层中的称谓
- 数据帧(Frame):是一种信息单位,它的起始点和目的点都是数据链路层。
- 数据包(Packet):也是一种信息单位,它的起始和目的地是网络层。
- 段(Segment):通常是指起始点和目的地都是传输层的信息单元。
- 消息(message):是指起始点和目的地都在网络层以上(经常在应用层)的信息单元。

网络协议
- HTTP HTTPS 是应用层协议
- TCP UDP FTP TFTP 是传输层协议
- IP ICMP 是网络层协议
- ARP RARP 是数据链路层协议
- 以太网协议是物理层协议
http 和浏览器出现之前,人们是如何浏览网页的?
TCP/IP 协议族
- 70 年代,互联网出现,但是只能传输文本,不能传输图片、视频等
- TCP/IP 协议(Transmission Control Protocol/Internet Protocol,传输控制协议/网际协议)1971 年
- TSMTP 协议(Trivial Simple Mail Transfer Protocol,简单邮件传输协议)1971 年
- FTP 协议(File Transfer Protocol,文件传输协议)1971 年
- Telnet 协议(Telnet,远程登录协议)1973 年
www 万维网
- HTTP 协议(HyperText Transfer Protocol,超文本传输协议)
- HTML 语言(Hyper Text Markup Language,超文本标记语言)
- URL(Uniform Resource Locator,统一资源定位符)
http://user:password@host:port/path?query#fragment
- HTTP 协议是建立在 TCP 协议之上的
HTTP 特点
- 请求应答模式
- 灵活可扩展
- 可靠传输
- 无状态(cookie、session)
HTTP 为什么不安全?
- 泄露
- 冒充
- 篡改
对称加密(共享密钥加密)
- DES Data Encryption Standard,数据加密标准
- 秘钥 8 字节
- encrypt(data, key) 加密
- decrypt(data, key) 解密
非对称加密(公钥加密,私钥解密)
- RSA Rivest-Shamir-Adleman
- 公钥加密,私钥解密
- 存储秘钥成本低(公钥只有一个,不用一个客户端生成一个秘钥)
证书
- 提交:域名、公司名称、公司地址、公司电话、公司邮箱、公司营业执照等信息
- 证书包含:颁发者、有效期、公钥、签名、有效期等
- 正规的网站如果使用免费的证书,会让人觉得不靠谱,快要倒闭的感觉、形象不太好
中间人攻击 MITM Man In The Middle
- 银行给客户端发送公钥时被劫持,客户端收到的公钥是中间人伪造的公钥,客户端用伪造的公钥加密数据,中间人用自己的私钥解密数据,然后用银行的公钥加密数据,银行用自己的私钥解密数据,这样中间人就可以看到客户端和银行的通信内容了
- 伪造证书颁发机构(一般找权威的 GlobalSign Organization)
- 如果骗子冒充你的身份,用他的域名去办证书会怎么样?证书需要提供公司的营业执照等信息,骗子提供不了银行等大公司的营业执照
- 证书可以公开导出,骗子网站把你的证书放到他的网站上,冒充你怎么办?浏览器会检查域名,域名和证书不匹配,会提示证书不安全
- 骗子把你证书里面的公钥换成他自己的怎么办?需要用指纹
如何保证公钥不被篡改?
- CA 用
哈希算法对服务器公钥生成摘要(哈希值),加密后得到指纹 - 客户端用
哈希算法对服务器公钥生成摘要(哈希值),解密指纹,对比摘要
如何证明身份?
- 数字证书 Digital Certificate
- 证书颁发机构 CA Certificate Authority
TCP 三次握手
在 TCP 三次握手中,SYN 是指"同步序列编号"(Synchronize Sequence Numbers),ACK 是指"确认序号"(Acknowledgement)。
- 客户端向服务器发送一个 SYN 报文段,表示客户端请求建立连接。
- 服务器收到客户端的 SYN 报文段后,向客户端发送一个 ACK 报文段,表示服务器已收到客户端的请求,准备好建立连接。
- 客户端收到服务器的 ACK 报文段后,也向服务器发送一个 ACK 报文段,表示客户端已收到服务器的确认,TCP 连接已经建立。
https
TLS 协议
TLS 的全称是 Transport Layer Security,中文名为传输层安全协议,是一种常用的基于加密的网络传输协议。TLS 协议是为了解决早期的 SSL 协议存在的安全漏洞和缺陷而被设计出来的,属于 HTTPS 协议的基础。
分层模型
下层是为上层提供服务的,上层提供请求和数据,下层进行处理

七层可以类比成给人写信
应用层代表写信的内容,表示层、会话层、传输层表示信的传输目标(地址、收件人),网络层是寻址、找目的地的过程,数据链路层和物理层表示真正传输的过程。
物理层:传输是 0、1 传输,可能拿 0V 电压代表 0,5V 代表 1(网线、光纤、wifi 等实体),为上层数据链路层提供服务通道
数据链路层:数据传输,需要物理层
网络层:找到路线到目的地(最短),不关心中间传输的错误,不可靠,可靠性需要传输层。
传输层:传输的过程中,每隔一个路线的节点或者一小段时间内,就向回返回一个到达的讯息,如果没有返回讯息,就会重新传递。直到到达目的地,返回一个到达目的地的讯息才算结束。在不可靠的网络层上,传递可靠的网络数据,这就是传输层
封装过程

客户端和服务器端交互模型
- 打开一个浏览器, 在地址栏输入一个网址, 按下 ENTER 键, 到看到整页面, 中间都经历了哪些事情?
HTTP 请求阶段: 向服务器发送请求
- 浏览器首先向 DNS 域名解析服务器发送请求
- DNS 反解析: 根据浏览器请求地址中的域名, 到 DNS 服务器中找到对应的服务器外网 IP 地址
- 通过找到的外网 IP, 向对应的服务器发送请求(首先访问的是服务器的 WEB 站点管理工具: 准确来说是我们先基于工具在服务器上创建很多服务, 当有客户端访问的时候, 服务器会匹配出具体是请求哪个服务)
- 通过 URL 地址中携带的端口号, 找到服务器上对应的服务, 以及服务所管理的项目源文件
HTTP 响应阶段: 服务器把客户端需要的内容准备好, 并且返回给客户端
- 服务器端根据请求地址中的路径名称, 问号传参或者哈希值, 把客户端需要的内容进行准备和处理
- 把准备的内容响应给客户端(如果请求的是 HTML 或者 CSS 等这样的资源文件, 服务器返回的是资源文件中的源代码[不是文件本身])
浏览器渲染阶段
客户端浏览器接收到服务器返回的源代码, 基于自己内部的渲染引擎(内核)开始进行页面的绘制和渲染
首先计算 DOM 结构, 生成 DOM TREE
自上而下运行代码, 加载 CSS 等资源内容
根据获取的 CSS 生成带样式的 RENDER TREE
开始渲染和绘制

- 我们把完整的 请求+响应 称之为"HTTP 事务"
事务就是完整的一次操作, 请求和响应缺一不可
- 一个页面完全加载完成, 需要向服务器发起很多次 HTTP 事务操作
一般来说: 首先把 HTML 源代码拿回来, 加载 HTML 的时候, 遇到 link/script/img[src]/iframe/video 和 audio[没有设置 preload='none']...都会重新和服务器端建立 HTTP 事务交互
特殊情况: 如果我们做了资源缓存处理(304), 而且即将加载的资源在之前已经加载过了, 这样的操作和传统的 HTTP 事务有所不一样, 他们是从服务器和浏览器的缓存中读取数据, 比传统的读取快很多
- HTTP 报文
客户端向服务器发送请求, 以及服务器把内容响应给客户端的时候, 中间相互传递了很多内容(客户端把一些内容传递服务器, 服务器把一些内容响应给客户端), 我们把传递的内容统称为"HTTP 报文"
一个完整的 URL 各部分分析
下面拿网址展开知识:http://www.zhufengpeixun.cn:80/stu/index.html?name=xxx&age=25#teacher
- URL/URN/URI
URI=URN+URL URI: 统一资源标识符 URL: 统一资源定位符 URN: 统一资源名称
- 传输协议
用来传输客户端和服务器端交互的信息的 HTTP: 超文本传输协议(除了传递普通的文本, 还可以传递文件流或者进制编码等信息), 是目前最常用的 WEB 传输协议 HTTPS: 基于 SSL(Secure Sockets Layer 安全套接层)加密的 HTTP 传输协议, 比 HTTP 更加的安全(涉及支付的网站一般都是基于 HTTPS 完成的) FTP: 文件传输协议, 一般用来实现资源文件在服务器上的上传下载 (类似于快递, HTTPS 安全类似邮政, HTTP 类似普通的快递顺丰)
- 域名(Domain Name)
一级域名(顶级域名): <www.qq.com> 二级域名: sports.qq.com 三级域名: kbs.sports.qq.com .com 供商用的国际域名 .cn 供商用的中文域名 .net 用于网络供应服务商(系统类的经常使用 NET 域名) .org 用于官方组织 .edu 用于教育元宵 .gov 用于政府机构
- 端口号
用来区分同一台服务器上不同服务的标识(类似 WEB 服务管理器常见服务的时候可以指定), 不同服务之间一般是不能使用相同的端口号的 HTTP 默认端口号 80 HTTPS 默认端口号 443 FTP 默认端口号 21 如果当前网站服务, 采用的是协议对应的默认端口管理, 那么当用户输入网址的时候可以不指定端口号, 浏览器会默认对用户使用默认的端口传递给服务器
一台服务器上的端口号范围: 0~65535 之间
webStorm 预览页面: webStorm 把自己的电脑当做服务器, 在服务器上创建一个服务, 端口号是 63342, 自己电脑上的浏览器预览自己电脑上的服务, 属于本机服务请求, 用 localhost(127.0.0.1)本地域名即可
服务器上安装一款应用都可能会作为一个服务, 占用一个端口号
- 请求路径名称
path pathname 例如: /stu/index.html 一般都是请求当前服务对应的项目目录中, stu 文件夹中的 index.html 页面. 但是也有特殊情况, 就时当前的 URL 是被"伪 URL 重写"的, 我们看到的 URL 请求其实不是真实的请求(例如: https://item.jd.com/4679424.html 这个 URL 就是被重写的,
它的真实 URL 地址很可能是 https://item.jd.com/detail.jsp?id=4679424, 其实就是跳转到详情页, 通过问号传递不同的产品编号, 展示不同的产品详情信息, 但是 jsp 这种服务器渲染的动态页面不能被搜索引擎收录, 不利于页面的 SEO, 所以我们会把动态页面静态化, 这也就用到了 URL 重写技术)
例如: /stu/info 这种没有任何后缀信息, 一般都不是用来请求资源文件的, 而是用于 AJAX 数据请求的接口地址(如果后缀是.json 类的, 也是同理), 但是有一种除外 /stu/info/ 这种的很可能不是接口地址, 而是没有指定请求的资源名称, 服务器会请求默认的资源文件, 一般都是 index.html/default.html...
DHTML: 动态页面, 泛指当前页面中的内容不是写死的而是动态绑定的, 例如: jsp/.php/.aspx... 这些页面中的数据都是基于 AJAX 或者是后台编程语言处理, 由服务器端渲染, 最后把渲染后的结果返回给客户端呈现的
.jsp是 JAVA 用的, .php是 PHP 用的, .asp/.aspx是 C#或者.NET 用的
- 问号传参及哈希值
?xxx=xxx&...#xxx 在 HTTP 事务中, 问号传参是客户端把信息传递给服务器的一种方式(也有可能是跳转到某一个页面, 把参数值传递给页面用来标识的) 哈希值一般都跟客户端服务器端交互没什么关系, 主要用于页面中的锚点定位和 HASH 路由切换
HTTP 报文

- General 通用头
Request URL: http://www.zhufengpeixun.cn/ 请求地址
Request Method: GET 请求方式:GET/POST/DELETE/PUT/HEAD/OPTION...
Status Code: 304 Not Modified 响应的HTTP状态码
Remote Address: 125.39.174.137:80 主机地址(服务器外网IP地址)
Referrer Policy: no-referrer-when-downgrade
- Request Headers 请求头
GET / HTTP/1.1 起始行(描述当前请求的一些基本信息:用的是1.1版本传输协议进行内容传输的)
Host: www.zhufengpeixun.cn
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: ... cookie信息一般都是放到头文件中实现和服务器端的数据通信的
If-Modified-Since: Sun, 06 May 2018 10:02:42 GMT
- Response Headers 响应头
HTTP/1.1 304 Not Modified 响应起始行(HTTP状态码)
Date: Tue, 22 May 2018 09:18:56 GMT 服务器响应内容时候的“服务器端时间”(客户端获取这个时间的时候已经和真实的时间产生误差了,因为服务器返回内容到客户端接收到,也是需要时间的),并且这个时间是格林尼治时间(比北京时间慢8小时,北京时间是GMT+0800)
Connection: keep-alive
ETag: "700a6f-17f43-56b86a77513d3"
Vary: Accept-Encoding,User-Agent
Server: yunjiasu-nginx 管理WEB服务的工具
CF-RAY: 41ee32c192db66b8-TSN
主要性能优化技巧
在 JS 中尽量减少闭包的使用(原因: 闭包会产生不释放的栈内存) A: 循环给元素做事件绑定的时候, 尽可能的把后期需要的信息(例如索引)存储到元素的自定义属性上, 而不是创建闭包存储 B: 可以在最外层形成一个闭包, 把一些后续需要的公共信息进行存储, 而不是每一个方法都创建闭包(例如单例模式) C: 尽可能的手动释放不被占用的内存 ...
尽量合并 css 和 js 文件(把需要引入的 css 合并为一个, js 也合并为一个), 原理是在减少 HTTP 请求次数, 尽可能的把合并后的代码进行压缩, 减少 HTTP 请求资源的大小 A: webpack 这种自动化构建工具, 可以帮我们实现代码的合并和压缩(工程化开发) B: 在移动开发(或者追求高性能的 PC 端开发, 例如百度首页), 如果 CSS 或者 JS 不是需要很多, 我们可以选择把 css 和 js 编程内嵌式(也就是代码直接写在 HTML 中)
尽量使用字体图标或者 SVG 图标, 来代替传统的 PNG 等格式的图片(因为字体图标等是矢量图(基于代码编写出来的), 放大不会变形, 而且渲染速度快, 相对比位图要小一些)
减少对 DOM 的操作(主要是减少 DOM 的重绘和回流(重排)) A: 关于重排的分离读写 B: 使用文档碎片或者字符串拼接做数据绑定(DOM 的动态创建)
在 JS 中避免"嵌套循环" (这种会额外增加很多循环次数) 和 "死循环" (一旦遇到死循环浏览器就卡壳了)
采用图片的"懒加载"(延迟加载) 目的是为了减少页面"第一次加载"过程中 HTTP 的请求次数, 让页面打开速度变快 步骤: 开始加载页面的时候, 所有的真实图片都不去发送 HTTP 请求加载, 而是给一张占位的背景图, 当页面加载完并且图片在可视区域内我们再去做图片加载
利用浏览器和服务器端的缓存技术(304 缓存), 把一些不经常更新的静态资源文件做缓存处理(例如: JS,CSS,静态图片等都可以做缓存) 原理是为了减少 HTTP 请求大小, 让获取速度更快
尽可能使用事件委托(事件代理)来处理事件绑定的操作, 减少 DOM 的频繁操作, 其中包括给每一个 DOM 元素做事件绑定
尽量减少 CSS 表达式的使用(expression)
#myDiv {
position: absolute;
width: 100px;
height: 100px;
left: expression(document.body.offsetWidth - 110 + "px");
top: expression(document.body.offsetHeight - 110 + "px");
background: red;
}
- CSS 选择器解析规则是从右向左解析
.container .link a {
// 先找到所有的a, 再筛选是在.link样式类中的, 再次筛选是在.container样式类中的
// 先找到的是所有的a, 操作起来是消耗性能的, 我们在使用css选择器的视乎尽可能减少对标签选择器的使用
}
- CSS 雪碧图技术(css sprite / css 图片精灵) 把所有相对较小资源图片汇总到一张大图上, 后期我们只需要把大图加载下来, 用背景定位的方式展示对应的小图即可
.bg{
background:url('xxx.png');
}
.box1{
background-position:xx xx;
}
.box2{
background-position:xx xx;
}
<div class='bg box1'></div>
- 减少对于 cookie 的使用(最主要的是减少本地 cookie 存储内容的大小), 因为客户端操作 cookie 的时候, 这些信息总是在客户端和服务端传来传去
- 页面中的数据获取采用异步编程和延迟分批加载 使用异步获取数据, 是为了降低 HTTP 通道的堵塞, 不会因为数据没有请求回来耽误下面信息的渲染, 提高页面的打开速度(我们可以这样处理: 需要动态绑定数据的区域先隐藏, 等待数据返回并且绑定完成后再让其显示) 延迟分批加载类似于图片懒加载, 是为了减少第一次页面加载时候的 HTTP 请求次数
- 页面中出现音视频标签, 我们不让页面加载的时候就去加载这些资源(要不然页面加载速度会变慢) 方案: 只需要设置 preload='none'即可, 等待页面加载完成, 音视频播放的时候我们再去加载音视频资源
- 在客户端和服务端进行信息交互的时候, 对于多项数据我们尽可能基于 JSON 格式来进行传送(JSON 格式的数据处理方便, 资源偏小) 相对于 XML 格式的传输才会有这个优势
- 尽可能实现 JS 的封装(低耦合高内聚), 减少页面中的冗余代码(减少 HTTP 请求资源的大小)
- CSS 中设置定位后, 最好使用 z-index 改变盒子的层级, 让所有的盒子不在相同的平面上, 这样后续处理的时候, 性能有那么一点点的提高
- 在基于 AJAX 的 GET 请求进行数据交互的时候, 根据需求可以让其产生缓存(这个缓存不是 304 缓存), 这样下一次从相同地址获取的数据是上一次缓存的数据(但是很少用, 项目中一般刻意清除这个缓存的时候偏多)
- 尽量减少对于 filter 滤镜的使用(这个属性消耗性能较大一些)
- 在 CSS 导入的时候尽量减少使用@import 导入式, 因为@import 是同步操作, 只有把这个对应的 CSS 导入, 才会向下加载, 而 link 是异步操作
- 配置 ETag(有点类似于 304 缓存)
- 使用 window.requestAnimationFrame(JS 中的帧动画)代替传统的定时器动画
- 减少递归的使用, 避免死递归, 避免由于递归导致的栈内存嵌套(建议使用尾递归)
- 避免使用 iframe(不仅不好管控样式, 而且相当于在 a 页面中加载了其他页面, 消耗较大)
- 利用 h5 中提供的 loaclstorage 本地存储或者是 manifest 离线缓存, 做一些信息的本地存储, 下一次加载页面的时候直接从本地获取, 减少 HTTP 请求次数
- 基于 script 调取 JS 的时候, 可以使用 defer 或者 async 来异步加载
- 重量级优化: 做 CDN 加速(烧钱机器)

额外技巧
- 我们一般都把 css 放到 body 上, 把 js 放到 body 下(原因: 让其先加载 css 再加载, 先加载 css 是为了保证页面渲染的过程中, 元素时带着样式渲染的, 而 js 一般都是用来操作 DOM 元素的, 需要等到元素加载完再操作)
- 能用 css 搞定的绝对不用 js, 能用原生 js 搞定的绝对不用插件, 绝对不使用 flash(除了音视频的低版本浏览器播放) css 处理动画等功能的性能优于 js, 而且 css 中的 transform 变形还开启了硬件加速
- js 中尽量减少对 eval 的使用, 因为 js 合并压缩的时候, 可能出现由于符号不完善, 导致的代码进行优先级错乱问题, eval 处理起来消耗的性能也是偏大一点的
- 使用 keep-alive 实现客户端和服务端的长连接
- 尽量使用设计模式来管理我们的代码(单例, 构造, Promise, 发布订阅), 方便后期的升级和维护
- 开启服务器端的 gzip 压缩(这个压缩可以有效减少请求资源文件的大小), 其实客户端的图片等资源也是可以进行压缩的(但是对于 24 位的位图, 压缩后可能会变模糊)
- 页面中不要出现无效的链接(利于 SEO 优化), 还有其他技巧: 提高关键字曝光率, img 需要加 alt, 设置 meta 标签, 标签语义化...
- 避免使用 with 语句(非常耗性能)
