响应式设计

引言 响应式布局指的是同一页面在不同屏幕尺寸下有不同的布局。传统的开发方式是PC端开发一套,手机端再开发一套,而使用响应式布局只要开发一套就够,缺点就是CSS比较重。下面是博客网站对不同设备适配后的结果,分别是iPhone5/SE,iphone6/7/8,iphone 6/7/8 plus,ipad pro,dell台式宽屏(1440 X 900)。 响应式设计与自适应设计的区别:响应式开发一套界面,通过检测视口分辨率,针对不同客户端在客户端做代码处理,来展现不同的布局和内容;自适应需要开发多套界面,通过检测视口分辨率,来判断当前访问的设备是pc端、平板、手机,从而请求服务层,返回不同的页面。 响应式布局的实现方案 1. 媒体查询 CSS3媒体查询可以让我们针对不同的媒体类型定义不同的样式,当重置浏览器窗口大小的过程中,页面也会根据浏览器的宽度和高度重新渲染页面。 如何选择屏幕大小分割点 如何确定媒体查询的分割点也是一个开发中会遇到的问题,下面是市场上的移动设备和电脑屏幕分辨率的分布情况,可以发现不同品牌和型号的设备屏幕分辨率一般都不一样 如果我们选择600px,900px,1200px,1800px作为分割点,可以适配到常见的14个机型: 当然这只是其中的一种分割方案,我们还可以这样划分:480px,800px,1400px,1400px 而作为曾经典型的响应式布局框架,Bootstrap是怎么进行断点的呢? 上面的分割方案不一定满足项目中的实际需求,我们可以先用跨度大的分割点进行分割,如果出现不适配的情况可以再根据实际情况增加新的分割点。 移动优先 OR PC优先 不管是移动优先还是PC优先,都是依据当随着屏幕宽度增大或减小的时候,后面的样式会覆盖前面的样式。因此,移动端优先首先使用的是min-width,PC端优先使用的max-width。 移动优先: /* iphone6 7 8 */ body { background-color: yellow; } /* iphone 5 */ @media screen and (max-width: 320px) { body { background-color: red; } } /* iphoneX */ @media screen and (min-width: 375px) and (-webkit-device-pixel-ratio: 3) { body { background-color: #0FF000; } } /* iphone6 7 8 plus */ @media screen and (min-width: 414px) { body { background-color: blue; } } /* ipad */ @media screen and (min-width: 768px) { body { background-color: green; } } /* ipad pro */ @media screen and (min-width: 1024px) { body { background-color: #FF00FF; } } /* pc */ @media screen and (min-width: 1100px) { body { background-color: black; } } PC优先: ...

October 8, 2024

vue路由

从后端路由开始 路由这个概念最先是后端出现的。在以前用模板引擎开发页面时,经常会看到这样 http://www.xxx.com/login 大致流程可以看成这样: 浏览器发出请求 服务器监听到80端口(或443)有请求过来,并解析url路径 根据服务器的路由配置,返回相应信息(可以是 html 字串,也可以是 json 数据,图片等) 浏览器根据数据包的 Content-Type 来决定如何解析数据 简单来说路由就是用来跟后端服务器进行交互的一种方式,通过不同的路径,来请求不同的资源,请求不同的页面是路由的其中一种功能。 前端路由 1. hash 模式 随着 ajax 的流行,异步数据请求交互运行在不刷新浏览器的情况下进行。而异步交互体验的更高级版本就是 SPA —— 单页应用。单页应用不仅仅是在页面交互是无刷新的,连页面跳转都是无刷新的,为了实现单页应用,所以就有了前端路由。 类似于服务端路由,前端路由实现起来其实也很简单,就是匹配不同的 url 路径,进行解析,然后动态的渲染出区域 html 内容。但是这样存在一个问题,就是 url 每次变化的时候,都会造成页面的刷新。那解决问题的思路便是在改变 url 的情况下,保证页面的不刷新。在 2014 年之前,大家是通过 hash 来实现路由,url hash 就是类似于: http://www.xxx.com/#/login 这种 #。后面 hash 值的变化,并不会导致浏览器向服务器发出请求,浏览器不发出请求,也就不会刷新页面。另外每次 hash 值的变化,还会触发hashchange 这个事件,通过这个事件我们就可以知道 hash 值发生了哪些变化。然后我们便可以监听hashchange来实现更新页面部分内容的操作: function matchAndUpdate () { // todo 匹配 hash 做 dom 更新操作 } window.addEventListener('hashchange', matchAndUpdate) 2. history 模式 14年后,因为HTML5标准发布。多了两个 API,pushState 和 replaceState,通过这两个 API 可以改变 url 地址且不会发送请求。同时还有popstate 事件。通过这些就能用另一种方式来实现前端路由了,但原理都是跟 hash 实现相同的。用了 HTML5 的实现,单页路由的 url 就不会多出一个#,变得更加美观。但因为没有 # 号,所以当用户刷新页面之类的操作时,浏览器还是会给服务器发送请求。为了避免出现这种情况,所以这个实现需要服务器的支持,需要把所有路由都重定向到根页面。 ...

October 5, 2024

事件冒泡、事件捕获、事件委托

DOM事件流(event flow )存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。 Dom标准事件流的触发的先后顺序为:先捕获再冒泡。即当触发dom事件时,会先进行事件捕获,捕获到事件源之后通过事件传播进行事件冒泡。 addEventListener的第三个参数 在我们平常用的addEventListener方法中,一般只会用到两个参数,一个是需要绑定的事件,另一个是触发事件后要执行的函数,然而addEventListener还可以传入第三个参数: element.addEventListener(event, function, useCapture); 第三个参数默认值是false,表示在事件冒泡阶段调用事件处理函数;如果参数为true,则表示在事件捕获阶段调用处理函数。如果不写第三个参数则默认在事件冒泡阶段调用事件处理函数。 下面先介绍事件冒泡: 1. 事件冒泡 事件冒泡(dubbed bubbling):当一个元素接收到事件的时候,会把他接收到的事件传给自己的父级,一直到 window (注意这里传递的仅仅是事件,例如click、focus等等这些事件, 并不传递所绑定的事件函数。) 事件源 =>根节点(由内到外)进行事件传播。 举例说明: 给三个盒子依次绑定点击事件,当点击盒子的时候,会依次触发父级元素的点击事件。 click small box click center box click big box 如果父元素没有绑定点击事件则只会触发点击盒子的事件。 click small box 如果子元素(small)的点击事件去掉,当我们点击small的时候会把当前操作的点击事件传递给父元素(因为父元素绑定了点击函数) click small box 有些时候我们不希望产生事件冒泡,所以可以 在子事件中加入e.stopPropagation() 取消冒泡 click small box 2. 事件捕获 事件捕获(event capturing): 当鼠标点击或者触发dom事件时(被触发dom事件的这个元素被叫作事件源),浏览器会从根节点 =>事件源(由外到内)进行事件传播。 事件捕获与事件冒泡是比较类似的,最大的不同在于事件传播的方向。 还是举上面的例子: click small box 3. 事件委托 事件委托也称为事件代理。就是利用事件冒泡,把子元素的事件都绑定到父元素上。如果子元素阻止了事件冒泡,那么委托就无法实现。 原理实现: 不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。 应用场景:1000个button需要注册点击事件 如果循环给每个按钮添加点击事件,那么会增加内存损耗,影响性能 此时可以给button的父元素添加点击事件 这时相当于每个按钮都绑定了点击事件 优点: 替代循环绑定事件的操作,减少内存消耗,提高性能。比如: 在table上代理所有td的click事件。 在ul上代理所有li的click事件。 简化了dom节点更新时,相应事件的更新。比如: 不用在新添加的li上绑定click事件。 当删除某个li时,不用移解绑上面的click事件。 缺点: ...

October 1, 2024

浏览器渲染过程中的网络层面

一、梳理主干流程 知识体系中,最重要的是骨架,脉络。有了骨架后,才方便填充细节。所以,先梳理下主干流程: 浏览器接收url并开启一个新进程(这一部分可以展开浏览器的进程与线程的关系) 浏览器解析输入的 URL,提取出其中的协议、域名和路径等信息。(这部分涉及URL组成部分) 浏览器向 DNS 服务器发送请求,DNS服务器通过 多层查询 将该 域名 解析为对应的 IP地址 ,然后将请求发送到该IP地址上,与 服务器 建立连接和交换数据。(这部分涉及DNS查询) 浏览器与服务器建立 TCP 连接。(这部分涉及TCP三次握手/四次挥手/5层网络协议) 浏览器向服务器发送 HTTP 请求,包含请求头和请求体。(4,5,6,7包含http头部、响应码、报文结构、cookie等知识) 服务器接收并处理请求,并返回响应数据,包含状态码、响应头和响应体。 浏览器接收到响应数据,解析响应头和响应体,并根据状态码判断是否成功。 如果响应成功,浏览器接收到http数据包后的解析流程(这部分涉及到html - 词法分析,解析成DOM树,解析CSS生成CSSOM树(样式树),合并生成render渲染树(样式计算)。然后layout布局,分层,调用GPU绘制等,最后将绘制的结果合成最终的页面图像,显示在屏幕上。这个过程会发生回流和重绘)。 连接结束 -> 断开TCP连接 四次挥手 梳理出主干骨架,然后就需要往骨架上填充细节内容。 接下来重点介绍“浏览器渲染过程中的网络层面”。 二、浏览器接收url并开启一个新进程 这部分内容开始之前我们需要先通过一张图对 进程 和 线程 的关系有一个初步的了解。 1. 浏览器是多进程的 浏览器是多进程的,有一个主进程,每打开一个tab页面都会新开一个进程(某些情况下多个tab会合并进程)。 注意:在这里浏览器应该也有自己的优化机制,有时候打开多个tab页后,比如打开多个空白标签页。可以在Chrome任务管理器中看到,进程被合并了。 进程可能包括主进程,插件进程,GPU,tab页(浏览器内核)等等。 Browser进程:浏览器的主进程(负责协调、主控),只有一个。 第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建。 GPU进程:最多一个,用于3D绘制等。 浏览器渲染进程(浏览器内核)(内部是多线程的):默认每个Tab页面一个进程,互不影响。作用是页面渲染,脚本执行,事件处理等。(浏览器有时候会优化,如多个空白页合并成一个进程) 强化记忆:在浏览器中打开一个网页相当于新起了一个进程(进程内有自己的多线程) 下图以 chrome浏览器 为例。我们可以自己通过Chrome的更多工具 =》 任务管理器 自行验证查看,可以看到chrome的任务管理器中有多个进程(分别是每一个Tab页面有一个独立的进程,以及一个主进程) 然后能看到每个进程的内存资源信息以及cpu占有率。 2. 浏览器内核是多线程的 每一个tab页面可以看作是浏览器内核的一个进程,然后这个进程是多线程的,它有几大类子线程 GUI渲染线程:负责渲染浏览器界面,解析HTML,CSS,构建DOM树和RenderObject树,布局和绘制等。GUI渲染线程与JS引擎线程是互斥的。 JS引擎线程:也叫 JS 内核,负责解析执行 JS 脚本程序的主线程,例如 V8 引擎。JS引擎一直等待着任务队列中任务的到来,然后加以处理,一个Tab页(renderer进程)中无论什么时候都只有一个JS线程在运行JS程序。 事件触发线程:属于浏览器内核线程,主要用于控制事件,例如鼠标、键盘等,当事件被触发时,就会把事件的处理函数推进事件队列,等待 JS 引擎线程执行。 定时器触发线程:主要控制 setInterval和 setTimeout,用来计时,计时完毕后,则把定时器的处理函数推进事件队列中,等待 JS 引擎线程。 异步http请求线程:通过XMLHttpRequest连接后,通过浏览器新开的一个线程,监控readyState状态变更时,如果设置了该状态的回调函数,则将该状态的处理函数推进事件队列中,等待JS引擎线程执行。 ...

July 28, 2025

react 渲染机制

前言 文本分为两大部分讲解,一部分是首次挂载渲染原理,另一部分是更新和卸载原理,很多地方非常抽象,希望大家仔细阅读,不然容易脱节。废话不多话,开车!! 正文 在开始之前,需要一些前置知识才能帮助我们更好的理解整个渲染过程。首先就是生命周期(16版本之后),为什么要讲一下生命周期?跟渲染原理有关系吗?当然有,如果你不理解渲染原理的话,更新一个嵌套很深的组件你甚至连父与子生命周期执行的先后顺序都不知道。本文直接对照16版本之后的新生命周期进行讲解,就不讲解老版本了。 初探-生命周期 顾名思义,跟人生一样,生命周期就是一个组件从诞生到销毁的过程。React在组件的生命周期中注册了一系列的钩子函数,支持开发者在其中注入代码,并在适当的时机运行。这里指的生命周期仅针对于类组件中的钩子函数。因为生命周期不是本文的重点,所以Hooks中的新增的钩子函数在本文中均不涉及,可以以后出个Hooks原理篇。 从图中可以看到,我把生命周期分为了挂载阶段、更新阶段、卸载阶段三个阶段。同时,在挂载阶段和更新阶段都会运行getDerivedStateFromProps和render,卸载阶段很好理解,只有一个componentWillUnMount,在卸载组件之前做一些事情,通常用来清除定时器等副作用操作。那么挂载阶段和更新阶段中的生命周期我们来逐一看下每个运行点及作用。 1. constructor 在同一个类组件对象只会运行一次。所以经常来做一些初始化的操作。同一个组件对象被多次创建,它们的construcotr互不干扰。 注意:在construcotr中要尽量避免(最好禁止)使用setState。 我们都知道使用setState会造成页面的重新渲染,但是在初始化阶段,页面都还没有将真实DOM挂载到页面上,那么重新渲染的又有什么意义呢。除异步的情况,比如setInterval中使用setState是没问题的,因为在执行的时候页面早已渲染完成。但也最好不要,容易一些引起奇怪的问题。 constructor(props) { super(props); this.state = { num: 1 }; //不可以,直接Warning this.setState({ num: this.state.num + 1 }); //可以使用,但不建议 setInterval(()=>{ this.setState({ num: this.state.num + 1 }); }, 1000); } 2. 静态属性 static getDerivedStateFromProps 该方法是一个静态属性,在16版本之前不存在,在新版生命周期中主要用来取代componentWillMount和componentWillReceiveProps,因为这两个老生命周期方法在一些开发者不规范的使用下极容易产生一些反模式的bug。因为是静态方法,所以你在其中根本拿不到this,更不可能调用setState。 该方法在挂载阶段和更新阶段都会运行。它有两个参数props和state当前的属性值和状态。它的返回值会合并掉当前的状态(state)。 如果返回了非Object的值,那么它啥都不会做,如果返回的是Object,那么它将会跟当前的状态合并,可以理解为Object.assign。通常情况下,几乎不怎么使用该方法。 /** * 静态方法,首次挂载和更新渲染都会运行该方法 * @param {*} props 当前属性 * @param {*} state 当前状态 */ static getDerivedStateFromProps(props, state){ // return 1; //没用 return { num: 999, //合并到当前state对象 }; } 3. render 最重要的生命周期,没有之一。用来生成虚拟节点(vDom)树。该方法只要遇到需要重新渲染都会运行。同样的,在render中也严禁使用setState,因为会导致无限递归重新渲染导致爆栈。 ...

December 17, 2024

全屏API

在 HTML 中,可以通过调用浏览器的全屏 API 实现页面或页面中的某个元素全屏显示。全屏 API 是 HTML5 提供的一项功能,允许将元素切换为全屏模式。 使用全屏 API 实现全屏 全屏 API 提供了以下常用方法和属性: requestFullscreen():请求将元素设置为全屏模式。 exitFullscreen():退出全屏模式。 fullscreenElement:返回当前正在全屏显示的 DOM 元素,如果没有元素全屏,则返回 null。 fullscreenchange 事件:当全屏状态发生变化时触发,用来监听进入或退出全屏。 实现全屏的基本步骤 选择你希望全屏的元素。 使用 element.requestFullscreen() 方法来进入全屏。 使用 document.exitFullscreen() 来退出全屏模式。 示例代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>全屏示例</title> <style> #fullscreenContent { width: 100px; height: 100px; background-color: lightblue; margin: 50px auto; text-align: center; line-height: 100px; } </style> </head> <body> <div id="fullscreenContent">点击全屏</div> <button id="exitFullscreenBtn" style="display:none;">退出全屏</button> <script> const fullscreenContent = document.getElementById('fullscreenContent'); const exitFullscreenBtn = document.getElementById('exitFullscreenBtn'); // 进入全屏模式 fullscreenContent.addEventListener('click', function() { if (fullscreenContent.requestFullscreen) { fullscreenContent.requestFullscreen(); } else if (fullscreenContent.mozRequestFullScreen) { // Firefox fullscreenContent.mozRequestFullScreen(); } else if (fullscreenContent.webkitRequestFullscreen) { // Chrome, Safari and Opera fullscreenContent.webkitRequestFullscreen(); } else if (fullscreenContent.msRequestFullscreen) { // IE/Edge fullscreenContent.msRequestFullscreen(); } exitFullscreenBtn.style.display = 'inline-block'; }); // 退出全屏模式 exitFullscreenBtn.addEventListener('click', function() { if (document.exitFullscreen) { document.exitFullscreen(); } else if (document.mozCancelFullScreen) { // Firefox document.mozCancelFullScreen(); } else if (document.webkitExitFullscreen) { // Chrome, Safari and Opera document.webkitExitFullscreen(); } else if (document.msExitFullscreen) { // IE/Edge document.msExitFullscreen(); } exitFullscreenBtn.style.display = 'none'; }); // 监听全屏状态变化 document.addEventListener('fullscreenchange', () => { console.log('全屏状态发生变化'); }); </script> </body> </html> 代码解释 进入全屏:点击 #fullscreenContent 的 div 时,调用 requestFullscreen() 方法使该元素进入全屏模式。 退出全屏:点击按钮 #exitFullscreenBtn,调用 document.exitFullscreen() 退出全屏模式。 跨浏览器兼容性:由于部分浏览器的全屏 API 有不同的实现方法,代码中兼容了各个主流浏览器的实现(例如 Chrome, Firefox, Safari, Edge)。 监听全屏状态变化:使用 fullscreenchange 事件来监听当前全屏模式的变化,可以在进入或退出全屏时执行额外操作。 全屏 API 的一些注意事项 全屏 API 只能在用户交互(如点击或按键事件)后触发,不能通过脚本自动进入全屏模式,这是为了防止用户体验被打断。 不同浏览器的全屏 API 实现可能稍有不同,因此通常需要做一些兼容性处理。 在移动端设备上,全屏模式的行为可能与桌面端有所不同。 总结 HTML5 的全屏 API 提供了一种简单而直观的方法来让页面或元素进入全屏模式。通过 requestFullscreen() 方法可以将任意元素全屏显示,exitFullscreen() 则用来退出全屏模式。结合 fullscreenchange 事件可以对全屏状态进行监控,实现更加丰富的交互体验。 ...

October 17, 2024

变量

一、变量的声明 声明变量的时候,变量名前面要加两根连词线(--)。 body { --foo: #7F583F; --bar: #F7EFD2; } 上面代码中,body选择器里面声明了两个变量:--foo和--bar。 它们与color、font-size等正式属性没有什么不同,只是没有默认含义。所以 CSS 变量(CSS variable)又叫做**“CSS 自定义属性”**(CSS custom properties)。因为变量与自定义的 CSS 属性其实是一回事。 你可能会问,为什么选择两根连词线(--)表示变量?因为$foo被 Sass 用掉了,@foo被 Less 用掉了。为了不产生冲突,官方的 CSS 变量就改用两根连词线了。 各种值都可以放入 CSS 变量。 :root{ --main-color: #4d4e53; --main-bg: rgb(255, 255, 255); --logo-border-color: rebeccapurple; --header-height: 68px; --content-padding: 10px 20px; --base-line-height: 1.428571429; --transition-duration: .35s; --external-link: "external link"; --margin-top: calc(2vh + 20px); } 变量名大小写敏感,--header-color和--Header-Color是两个不同变量。 二、var() 函数 var()函数用于读取变量。 a { color: var(--foo); text-decoration-color: var(--bar); } var()函数还可以使用第二个参数,表示变量的默认值。如果该变量不存在,就会使用这个默认值。 color: var(--foo, #7F583F); 第二个参数不处理内部的逗号或空格,都视作参数的一部分。 ...

October 10, 2024

状态管理

本知识点将以 Pinia 为例,介绍 Vue 中的状态管理。 前言 Pinia简称小菠萝🍍,是一个专为Vue 3设计的现代化状态管理库,为Vue 3开发的,它提供了一种简单、可扩展和类型安全的方式来管理应用程序的状态。 与Vue 2中的Vuex相比,Pinia提供了更好的TypeScript支持,具有更好的类型定义和类型推断,可在编译时捕获错误,提供更高的代码可靠性和开发体验。它是专为Vue 3设计的,充分利用了Vue 3的新特性,如Composition API,以提供更直接、自然和灵活的状态管理体验。Pinia的核心概念是Store,它类似于Vuex中的模块,用于管理应用程序的状,可以将相关的状态和逻辑组合到单个Store中,使代码更清晰、结构更有组织性。除此之外海提供了许多有用的特性和功能,例如模块化组织、状态持久化、插件扩展等。 总的来说,Pinia是一个功能强大而灵活的状态管理解决方案,适用于各种规模的Vue 3应用程序。它提供了现代化的特性和工具,帮助我们更好地组织、管理和扩展应用程序的状态,同时提供了更好的类型安全和开发体验。 安装 运行安装命令 npm install pinia 在main.ts中引入 // main.ts import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue' const pinia = createPinia() const app = createApp(App) app.use(pinia) app.mount('#app') 初始化Store 新建stores文件,用于存放所有的store,然后创建index.ts。 同过 defineStore() 定义一个store,它接受一个参数作为仓库名称,也就是Id。它返回一个函数,默认我们使用user开头的风格来接收。第二个参数为一个Setup函数或者Option对象。 import { defineStore } from 'pinia' export const useUsersStore = defineStore('users', { // 其他配置... }) Option Store 这种方式熟悉Vuex的很了解,传入一个带有 state、actions 与 getters 属性的 Option 对象 export const userUsersStore = defineStore('users', { state: () => { return { name: 'inkun', current: 100 } }, getters: { getName: (state) => state.name + '🐔你好帅' }, actions:{ getUserInfo { ... } } }) 在 Option Store 中: ...

October 5, 2024

call、apply和bind

apply 和 call简介 在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。 JavaScript 的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。 比如 A 对象有一个方法,而 B 对象因为某种原因,也需要用到同样的方法,那么这时候不用单独为 B 对象扩展一个方法,可以直接借用 A 对象的方法。这样既完成了需求,又减少了内存的占用。 直接来看个例子: function fruits() {} fruits.prototype = { color: "red", say: function() { console.log("My color is " + this.color); }} var apple = new fruits();apple.say(); //My color is red 但是如果我们有一个对象 banana= {color : "yellow"} ,我们不想对它重新定义 say 方法,那么我们可以通过 call 或 apply 用 apple 的 say 方法: banana = { color: "yellow"}apple.say.call(banana); //My color is yellowapple.say.apply(banana); //My color is yellow apply、call 的区别 对于 apply、call 二者而言,作用完全一样,只是接受参数的方式不太一样。例如,有一个函数定义如下: ...

October 1, 2024

抓包工具

抓包的原理 什么是抓包? 抓包就是将网络传输发送与接收的数据包进行截获、重发、编辑、转存等操作,通过抓包可以: 分析网络问题 业务分析 分析网络信息流通量 网络大数据金融风险控制 探测企图入侵网络的攻击 探测由内部和外部的用户滥用网络资源 探测网络入侵后的影响 监测链接互联网宽频流量 监测网络使用流量(包括内部用户,外部用户和系统) 监测互联网和用户电脑的安全状态 渗透与欺骗 … 回顾下计算机网络知识,数据在网络上是以很小的帧的单位传输的,帧通过特定的称为网络驱动程序的程序进行成型,然后通过网卡发送到网线上,通过网线到达目的机器,在目的机器的一端执行相反的过程。接收端机器的以太网捕获到这些帧,并告诉操作系统帧已到达,然后对其进行存储。在这个传输和接收的过程,就可以使用抓包工具(Sniffers)进行抓包,作为前端开发者,通常是抓取应用层的 HTTP/HTTPS 的包。 HTTP/HTTPS 抓包原理 HTTP/HTTPS 是应用层使用的通信协议,常见的应用层体系结构是客户端-服务器体系。 对运行在不同端系统上的客户端程序和服务端程序是如何互相通信的么?实际上,在操作系统上的术语中,进行通信的实际上是进程而不是程序,一个进程可以被认为是运行在端系统中的一个程序。 在 web 应用程序中,一个客户浏览器进程与一台服务器进程进行会话交换报文。 浏览器进程需要知道接收进程的主机地址,以及定义在目的主机中的接收进程的标识符,也就是目的端口。 多数应用程序由通信进程对组成,每对中的两个进程互相发送报文。进程通过一个称为套接字的软件接口向网络发送报文和从网络接收报文。 进程可以类比一座房子,而它的套接字可以是它的门,套接字是应用层与运输层之间的端口。 知道了两个进程的通信流程,我们要怎么抓包呢?举一个生活中的例子,小明暗恋小雯,于是他写了一封情书,但他有点害羞,找了小雯的好朋友小花帮忙传递情书。这个时候,小花可以负责小雯与小明之间的情书传递,作为中间人,她可以偷偷查看他们的情书内容。 思路就是设置一个中间人进程负责抓包,每次目标进程之间的会话都先与中间人进程通信,再进行转发。 HTTP 抓包原理 在 http 标准中,没有对通信端身份验证的标准。对于服务器来说,它接收的 HTTP 请求报文只要格式符合规范,就发送响应报文。 对于客户端来说也是如此,它无法校验服务器的身份,比如它连接的 http://www.jecyu.com 的主机,但由于中间节点的存在,最终连接的可能是 http://www.jerry.com 的主机。 因此,对于 HTTP 抓包,无需做过多的处理,只需要让中间人负责转发客户端和服务端的数据包。 HTTPS 抓包原理 HTTP 是明文传输,容易受到中间人攻击,不安全。 HTTPS 语义仍然是 HTTP,只不过是在 HTTP 协议栈中 http 与 tcp 之间插入安全层 SSL/TSL。 安全层采用对称加密的方式加密传输数据和非对称加密的方式来传输对称密钥,解决 http 数据没有加密、无法验证身份、数据容易纂改三个核心问题。 HTTP + 加密 + 认证 + 完整性保护 = HTTPS ...

July 28, 2025