上篇面向面试编程之前端大体系过于长了,,决定拆出来一部分,写一些偏向于网络和服务端的东西。
🍉:暂未写出答案。
🍊:涉及算法和手写代码。
🔔:笔者在面试过程中真实遇到的题目
本篇目录
- 前端工程化
- 浏览器+网络+通信+安全
- NodeJS
- 其他
react和js相关在上篇,传送门
前端工程化
🔔Webpack工作流程
- 从entry里配置的module开始递归解析entry依赖的所有module
- 每找到一个module,就会根据配置的loader去找对应的转换规则
- 对module进行转换后,再解析出当前module依赖的module
- 这些模块会以entry为单位分组,一个entry和其所有依赖的module被分到一个组Chunk
- 最后webpack会把所有Chunk转换成文件输出
- 在整个流程中webpack会在恰当的时机执行plugin里定义的逻辑
🔔🍉 Webpack有哪些配置
🔔🍉 Webpack打包优化
loader和plugin的加载顺序问题
loader从后往前执行,原因是webpack选择了函数式编程的方式,所以loader的顺序变成了从右往左,如果webpack选择了pipe的方式,执行顺序就变成从左往右了
Loader和Plugin的区别?
- Loader 本质就是一个函数,在该函数中对接收到的内容进行转换,返回转换后的结果。因为 Webpack 只认识 JavaScript,所以Loader 就成了翻译官,对其他类型的资源进行转译的预处理工作。
- Plugin 就是插件,插件可以扩展Webpack的功能,在Webpack运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果。
关于Babel
- babel是什么,有什么作用?
- babel是一个 ES6 转码器,可以将 ES6 代码转为 ES5 代码,以便兼容那些还没支持ES6的平台
- 注意:babel是一个js编译器,但是只转译语法,不转译原生对象和部分新增的api(如set、promise),需要引入polyfill来解决
- 怎么使用babel
- Babel 的配置文件是.babelrc,存放在项目的根目录下,配置转码规则和插件。(官方提供规则集@babel/preset-env)
- 基本配置:{“presets”: [],”plugins”: []}
- 一些重要的模块
- @babel/register (作用:@babel/register模块改写require命令,为它加上一个钩子。此后,每当使用require加载.js、.jsx、.es和.es6后缀名的文件,就会先用 Babel 进行转码)
- @babel/core(作用:需要使用babel的API进行转码)
- babel/polyfill (作用:转换新的 API)
- babel的转换时怎么实现的
- 解析:把旧的代码解析为AST抽象语法树
- 转换:按照开发者给定的babel插件 定义的规则,转化为新的抽象语法树
- 生成:根据新的抽象语法树,生成代码
🍉treeshaking原理
🔔模块化
- CommonJS: 一个文件为一个模块;使用 exports.xxx = ... 或 module.exports = {...} 暴露模块;使用 require(...) 方法来引入一个模块;require(...) 是同步执行。
- AMD: 使用 define(...) 定义一个模块;使用 require(...) 加载一个模块(和 CommonJS 规范是相同的方法名,注意区分 CommonJS 和 RequireJS;依赖前置,提前执行。
- CMD: 一个文件为一个模块;使用 define(...) 定义一个模块(和 AMD 相似);使用 require(...) 加载一个模块(和 AMD 相似);尽可能懒执行(和 AMD 的不同点)。
- UMD: 判断是否支持 AMD,判断是否支持 CommonJS,如果都不支持,使用全局变量。
- ES Module (ESM): 引入模块用 import 关键字 或 import(...) 方法;暴露模块用 export 关键字;
AMD 依赖前置,CMD 依赖就近。
CommonJS 与 ES6 模块化的差异
- CommonJS 支持动态导入,也就是require(${path}/xx.js),ES6 目前还不支持,但是已有提案。
- CommonJS 是同步导入,ES6是异步导入。
- CommonJS 因为用于服务端,文件都在本地,同步导入即使卡住主线程影响也不大。
- ES6 因为用于浏览器,需要下载文件,如果也采用同步导入会对渲染有很大影响。
- CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
- CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值;另一方面,如果导出的值变了,导入的值也不会变,所以如果想更新值,必须重新导入一次。
- ES6 采用实时绑定的方式,导入和导出的值都指向同一个内存地址,所以导入的值会跟随导出的值变化。
- CommonJS 模块是运行时加载,ES6 模块是编译时加载。
- CommonJS 模块就是一个对象,在导入时先加载整个模块,生成一个对象(这个对象只有在脚本运行完才会生成),然后再从这个对象上读取方法,这种加载称为“运行时加载”
- ES6 模块不是对象,它的对外接口只是一种静态定义,在代码运行之前(即编译时)的静态解析阶段就完成了模块加载,比 CommonJS 模块的加载方式更高效。
- ES模块允许进行静态分析,从而实现像tree-shaking的优化,并提供诸如循环引用和动态绑定等高级功能。
前端路由
分为两个
hash
- hash采用#拼接
- 通过window.hash获取
- hash改变不会触发页面刷新
- 可以通过监听hashchange事件来监听
- 对变化的hash值执行不同的回调函数
- 浏览器支持比较好
history API
- 是HTML5的新API,通过window.history获取
- 主要有这几个主要的API:pushState、replaceState、go、back、forward
- 通过监听popstate事件来监听go、back、forward等用户触发的操作
- 如果想监听pushState、replaceState,需要进行额外的实现,重写监听函数
浏览器+网络+通信+安全
🔔从输入URL到页面渲染的过程
- 查找缓存
- DNS把URL解析为IP地址
- 建立TCP连接(三次握手)
- 开始通讯
- 渲染页面DOM树
- 关闭TCP连接(四次挥手)
中间引申的几个关键知识点
1. 浏览器缓存机制
- 强制缓存优先于协商缓存进行。
- 若强制缓存生效则直接使用缓存,若不生效则进行协商缓存。
- 协商缓存由服务器决定是否使用缓存
- 若协商缓存失效,那么代表该请求的缓存失效,重新获取请求结果,再存入浏览器缓存中。
- 生效则返回304,继续使用缓存
1. 强缓存:向浏览器缓存查找该请求结果,并根据该结果的缓存规则来决定是否使用
- 控制强制缓存的字段分别是Expires和Cache-Control,其中Cache-Control优先级比Expires高
- cache-control取值
- public:所有内容都将被缓存(客户端和代理服务器都可缓存)
- private:所有内容只有客户端可以缓存,Cache-Control的默认取值
- no-cache:客户端缓存内容,但是是否使用缓存则需要经过协商缓存来验证决定
- no-store:所有内容都不会被缓存,即不使用强制缓存,也不使用协商缓存
- max-age=xxx (xxx is numeric):缓存内容将在xxx秒后失效
2. 协商缓存:强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程
- 控制协商缓存的字段分别有:Last-Modified / If-Modified-Since和Etag / If-None-Match,其中Etag / If-None-Match的优先级比Last-Modified / If-Modified-Since高。
2. DNS域名解析过程
- 检查浏览器缓存
- 检查操作系统缓存,如hosts 文件。
- 检查路由器缓存
- 向ISP(网络服务提供商)的LDNS服务器查询
- 最后按照从根域名开始的地址开始层层解析
2.1 DNS安全问题
3. 三次握手
- 第一次握手: 建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;
- 第二次握手: 服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;
- 第三次握手: 客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
- 完成三次握手,客户端与服务器开始传送数据。
4. 四次挥手
- 第一次挥手是浏览器发完数据后,发送FIN请求断开连接。
- 第二次挥手是服务器发送ACK表示同意,如果在这一次服务器也发送FIN请求断开连接似乎也没有不妥,但考虑到服务器可能还有数据要发送,所以服务器发送FIN应该放在第三次挥手中。
- 这样浏览器需要返回ACK表示同意,也就是第四次挥手。
5. 浏览器渲染机制
- 浏览器通过 HTMLParser 根据深度遍历的原则把 HTML 解析成 DOM Tree。
- 浏览器通过 CSSParser 将 CSS 解析成 CSS Rule Tree(CSSOM Tree)。
- 浏览器将JavaScript通过DOM API或者CSSOM API将JS代码解析并应用到布局中,按要求呈现响应的结果。
- DOM树建立后根据CSS样式进行构建内部绘图模型,生成RenderObject树
- 根据网页层次结构构建RenderLayer树,同时构建虚拟绘图上下文
- painting:遍历 render tree,并调动硬件图形 API 来绘制每个节点。
- layout:or Reflow回流,当 render tree 中任一节点的几何尺寸发生改变,render tree就会重新布局,重新来计算所有节点在屏幕的位置。
- repaint:重绘,当 render tree 中任一元素样式属性(几何尺寸没改变)发生改变时,render tree 都会重新画,比如字体颜色,背景等变化。
6. 页面渲染优化
- HTML文档结构层次、样式结构层次尽量简单;
- 脚本尽量后放,放在前即可;
- 减少DOM操作、缓存DOM查找,尽量缓存访问DOM的样式信息,避免过度触发回流;
- 减少通过JavaScript代码修改元素样式,尽量使用修改class名方式操作样式或动画;
- 隐藏在屏幕外,或在页面滚动时,尽量停止动画;
- 涉及多域名的网站,可以开启域名预解析
关于HTTP协议和HTTPS协议
- HTTP协议:基于TCP实现的应用层协议
- HTTPS:在HTTP上建立TLS/SSL加密层,并对传输数据进行加密,是HTTP协议的安全版。
- 常用的报文字段
- 请求报文
- Accept:客户端能够处理的媒体类型(常用的有text/html, application/json)
- Host:访问资源所在的主机名
- Referer:请求是从哪个页面发起的
- User-Agent:将发起请求的浏览器和代理名称等信息发送给服务端,例如:User-Agent: Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36(KHTML, like Gecko) Chrome/63.0.3239.84 Mobile Safari/537.36
- 还有几个和缓存相关的header:If-Match、If-Modified-Since、If-None-Match、If-Range、If-Unmodified-Since
- 响应报文
- ETag: 实体资源的标识,可用来请求指定的资源。
- Retry-After:服务端告知客户端多久之后再重试,一般与503和3xx重定向类型的应答一起使用。
- Server:告知服务端当前使用的HTTP服务器应用程序的相关信息。
- 实体首部字段
- Allow:通知客户端,服务器所支持的请求方法。但服务器收到不支持的请求方法时,会以405(Method Not Allowed)作为响应。
- Content-Encoding:告知客户端,服务器对资源的内容编码。
- Content-Language:告知客户端,资源所使用的自然语言。
- Content-Length:告知客户端资源的长度
- Content-Location:告知客户端资源所在的位置。
- Content-Type:告知客户端资源的媒体类型,取值同请求首部字段中的Accept。
- Expires:告知客户端资源的失效日期。可用于对缓存的处理。
- Last-Modified:告知客户端资源最后一次修改的时间。
- 通用报文字段
- Cache-Control:控制缓存行为;
- Connection:管理持久连接,设置其值为Keep-Alive可实现长连接。
- Date:创建HTTP报文的日期和时间。
- 其他报文字段
- Cookie:属于请求型报文字段,在请求时添加Cookie, 以实现HTTP的状态记录。
- Set-Cookie:属于应答型报文字段。服务器给客户端传递Cookie信息时,就是通过此字段实现的。
- 请求报文
- 附图:TCP/IP四层网络模型

🔔HTTPS握手过程
- 有客户端发起的第一次握手,此次握手过程的主要目的是从服务端获取数字签名证书,服务端在发送数字签名证书之前要先确认客户端的SSL版本、加密算法等信息。
- 完成第一次握手后,接着进行第二次握手。第二次握手是在客户端收到证书后发起的,主要目的是将AES加解密使用的Key (Pre-master secret)发送给服务端。当然这个AES_KEY是使用第一次握手获取的公钥进行加密的。客户端收到这个使用公钥加密后的AES_KEY,使用服务端的私钥进行解密。这样客户端和服务端经过二次握手后都持有了AES加解密的KEY
- 当Client与Server端都持有AES_KEY后,就可以对HTTP报文进行加解密了。这里就不再是RSA了,而是使用对称加密,就算被第三方劫持,第三方也不知道密码。除非其中一个人把密码告诉第三方。这里使用对称加密也是为了提高HTTPS的性能。因为本身HTTPS所消耗的时间也是不可忽视的。
🔔HTTPS的优点
- why:HTTP协议采用明文传输信息,存在信息窃听、信息篡改和信息劫持的风险,而协议TLS/SSL具有身份验证、信息加密和完整性校验的功能,提高安全性。
- HTTPS主要作用
- 对数据进行加密,并建立一个信息安全通道,来保证传输过程中的数据安全
- 对网站服务器进行真实身份认证
- 实现过程:TLS/SSL的功能实现主要依赖于三类基本算法:散列函数Hash、对称加密和非对称加密,其利用非对称加密实现身份认证和密钥协商,对称加密算法采用协商的密钥对数据加密,基于散列函数验证信息的完整性。


http状态码
2XX(Success 成功状态码)
- 200:成功,表示从客户端发来的请求在服务器端被正常处理了
- 204:成功处理,但是无资源可返回。一般在只需要从客户端往服务器发送信息,而对客户端不需要发送新信息内容的情况下使用
- 206:部分内容 服务器成功处理了部分GET请求
3XX(Redirection 重定向状态码)
3XX 响应结果表明浏览器需要执行某些特殊的处理以正确处理请求
- 301:永久重定向。该状态码表示请求的资源已被分配了新的URI,以后应使用资源现在所指的URI。也就是说,如果已经把资源对应的 URI 保存为书签了,这时应该按 Location 首部字段提示的URI重新保存
- 302:临时重定向。 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求
- 303:查看其它位置 。该状态码表示由于请求对应的资源存在着另一个 URI,应使用 GET 方法定向获取请求的资源。
- 304:未修改。这个和重定向无关。代表自动上次请求后,请求的网页未修改过。服务器返回此响应,不会返回网页的内容
- 307:临时性重定向 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有的位置来进行以后的请求
4XX(Client Error 客户端错误状态码)
- 400:Bad Request。该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。另外,浏览器会像 200 OK 一样对待该状态码。
- 401:Unauthorized。未授权,请求要求身份验证。对于需要登录的网页,服务器可能返回此响应
- 403:Forbidden,禁止 服务器拒绝请求
- 404:Not Found,服务器找不到请求的网页
- 405:Method Not Allowed, 禁用请求中指定的方法,Access-Control-Allow-Methods查看允许使用的方法
5XX(Server Error 服务器错误状态码)
- 500:Internal Server Error,服务器内部错误
- 502:Bad Gateway,服务器作为网关或代理,从上游服务器无法收到无效响应
- 503:Service Unavailable,服务器不可用,服务器目前无法使用(由于超载或者停机维护)。通常,这只是暂时状态
- 504:网关超时,服务器作为网关代理,但是没有及时从上游服务器收到请求
http1.0、1.1、2.0 主要区别
http1.1(1999)和http1.0(1996)的区别
- 缓存处理,在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entitytag,If-Unmodified-Since,If-Match,If-None-Match等更多可供选择的缓存头来控制缓存策略。
- 带宽优化及网络连接的使用,HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(PartialContent),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
- 错误通知的管理,在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
- Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。
- 长连接,HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。
http2.0(2015)和http1.1的区别
- 新的二进制格式(BinaryFormat),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
- 多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。
- header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
- 服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。
http1.X的keep-alive和http2.0的多路复用的区别
- HTTP/1.* 一次请求-响应,建立一个连接,用完关闭;每一个请求都要建立一个连接
- HTTP/1.1 Pipeling解决方式为,若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某请求超时等,后续请求只能被阻塞,毫无办法,也就是人们常说的线头阻塞
- HTTP/2多个请求可同时在一个连接上并行执行。某个请求任务耗时严重,不会影响到其它连接的正常执行
多路复用有什么好处
- HTTP 性能优化的关键并不在于高带宽,而是低延迟。TCP连接会随着时间进行自我「调谐」,起初会限制连接的最大速度,如果数据成功传输,会随着时间的推移提高传输的速度。这种调谐则被称为 TCP 慢启动。由于这种原因,让原本就具有突发性和短时性的 HTTP 连接变的十分低效。
- HTTP/2 通过让所有数据流共用同一个连接,可以更有效地使用 TCP 连接,让高带宽也能真正的服务于 HTTP 的性能提升。
关于cookie
🔔如何取cookie和设置cookie
- 浏览器端获取:
document.cookie - 浏览器端设置:
document.cookie='testkey=hahah;path=/;domain=.juejin.im'
cookie 常用属性
- name
- value
- domin
- path
- Expires/Max-age:设置cookie有效期,expires是绝对时间、Max-age以秒为单位,为负数时,表示的是临时储存,不会生出cookie文件,只会存在浏览器内存中,且只会在打开的浏览器窗口或者子窗口有效,一旦浏览器关闭,cookie就会消失
- secure:当这个属性设置为true时,此cookie只会在https和ssl等安全协议下传输
- HttpOnly:如果这个属性设置为true,就不能通过js脚本来获取cookie的值,能有效的防止xss攻击
cookie、session、token几种鉴权方式使用时的注意事项
使用 cookie 时需要考虑的问题
- 因为存储在客户端,容易被客户端篡改,使用前需要验证合法性
- 不要存储敏感数据,比如用户密码,账户余额
- 使用 httpOnly 在一定程度上提高安全性
- 尽量减少 cookie 的体积,能存储的数据量不能超过 4kb
- 设置正确的 domain 和 path,减少数据传输
- cookie 无法跨域
- 一个浏览器针对一个网站最多存 20 个Cookie,浏览器一般只允许存放 300 个Cookie
- 移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token
使用 session 时需要考虑的问题
- 将 session 存储在服务器里面,当用户同时在线量比较多时,这些 session
- 会占据较多的内存,需要在服务端定期的去清理过期的 session
- 当网站采用集群部署的时候,会遇到多台 web 服务器之间如何做 session 共享的问题。因为 session 是由单个服务器创建的,但是处理用户请求的服务器不一定是那个创建session的服务器,那么该服务器就无法拿到之前已经放入到 session 中的登录凭证之类的信息了。
- 当多个应用要共享 session时,除了以上问题,还会遇到跨域问题,因为不同的应用可能部署的主机不一样,需要在各个应用做好 cookie 跨域的处理。
- sessionId 是存储在 cookie中的,假如浏览器禁止cookie或不支持cookie怎么办?一般会把sessionId 跟在 url 参数后面即重写 url,所以session不一定非得需要靠cookie实现移动端对cookie的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token
使用 token 时需要考虑的问题
- 如果你认为用数据库来存储token会导致查询时间太长,可以选择放在内存当中。比如redis很适合你对 token 查询的需求。
- token 完全由应用管理,所以它可以避开同源策略
- token 可以避免 CSRF 攻击(因为不需要 cookie 了)
- 移动端对 cookie 的支持不是很好,而 session 需要基于 cookie 实现,所以移动端常用的是 token
cookie、localstorage和sessionStorage区别
- 生命周期
- cookie:可设置失效时间,没有设置的话,默认是关闭浏览器后失效
- localStorage:除非被手动清除,否则将会永久保存。
- sessionStorage:仅在当前网页会话下有效,关闭页面或浏览器后就会被清除。
- 存放数据大小
- cookie:4KB左右
- localStorage和sessionStorage:可以保存5MB的信息。
- http请求
- cookie:每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题
- localStorage和sessionStorage:仅在客户端(即浏览器)中保存,不参与和服务器的通信
- 易用性
- cookie:需要程序员自己封装,源生的Cookie接口不友好
- localStorage和sessionStorage:源生接口可以接受,亦可再次封装来对Object和Array有更好的支持
GET和POST的区别
- GET 在浏览器回退时是无害的,而 POST 会再次提交请求。
- GET 产生的 URL 地址可以被 Bookmark,而 POST 不可以。
- GET 请求会被浏览器主动 cache,而 POST 不会,除非手动设置。
- GET 请求只能进行 url 编码,而 POST 支持多种编码方式。
- GET 请求参数会被完整保留在浏览器历史记录里,而 POST 中的参数不会被保留。
- GET 请求在 URL 中传送的参数是有长度限制的,而 POST 么有。
- 对参数的数据类型,GET 只接受 ASCII 字符,而 POST 没有限制。
- GET 比 POST 更不安全,因为参数直接暴露在 URL 上,所以不能用来传递敏感信息。
- GET 参数通过 URL 传递,POST 放在 Request body 中。
- GET 产生一个 TCP 数据包;POST 产生两个 TCP 数据包。对于 GET 方式的请求,浏览器会把 http header 和 data 一并发送出去,服务器响应200(返回数据);而对于 POST,浏览器先发送 header,服务器响应 100 continue,浏览器再发送 data,服务器响应 200 ok(返回数据)。
- GET 是请求获取指定资源,GET方法时安全、幂等、可缓存的,GET方法的报文主体没有任何语义。POST是根据报文主体来对指定资源做出处理,POST不安全(副作用),不幂等,不可缓存(大部分情况下)。
TCP和UDP比较
1. 基于连接与无连接,UDP是无连接的,即发送数据之前不需要建立连接。
2. TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付Tcp通过校验和,重传控制,序号标识,滑动窗口、确认应答实现可靠传输。如丢包时的重发控制,还可以对次序乱掉的分包进行顺序控制。
3. UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
4. 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信。
5. TCP对系统资源要求较多,UDP对系统资源要求较少。
🔔同源策略和跨域的几种方式
同源策略
相同协议,域名,端口。
JSONP
Web 页面上调用 js 文件不受浏览器同源策略的影响,所以通过 Script 便签可以进行跨域的请求。
-
首先前端先设置好回调函数,并将其作为 url 的参数。
-
服务端接收到请求后,通过该参数获得回调函数名,并将数据放在参数中将其返回。
-
收到结果后因为是 script 标签,所以浏览器会当做是脚本进行运行,从而达到跨域获取数据的目的。
-
优点: 兼容性很好,在古老的浏览器也能很好的运行;不需要 XMLHttpRequest 或 ActiveX 的支持;并且在请求完毕后可以通过调用 callback 的方式回传结果。
-
缺点: 它支持 GET 请求而不支持 POST 等其它类行的 HTTP 请求;它只支持跨域 HTTP 请求这种情况,不能解决不同域的两个页面或 iframe 之间进行数据通信的问题。
CORS
按照请求的方法和header 分为简单请求和非简单请求,两种处理方式不同,携带和返回的header也不同
简单请求
- methods: HEAD, GET, POST
- headers: 对 CORS 安全请求头集合 (CORS-safelisted request-header), Content-Type (application/x-www-form-urlencoded, multipart/form-data, text/plain)
不同时满足上面两个条件,就属于非简单请求。
-
对于简单请求:只在header里携带origin即可,
-
对于非简单请求,浏览器必须首先使用OPTIONS方法发起一个预检请求,从而获知服务端是否允许该跨域请求。
-
CORS 请求头:
- Origin (表明来源)
- 预检请求需要包含 Access-Control-Request-Method(请求即将使用的方法),Access-Control-Request-Headers(请求额外会携带的header)。
-
CORS 响应头:
- Access-Control-Allow-Origin:允许跨域的源,如果是*的时候,则无法携带cookie
- Access-Control-Allow-Credentials:允许传送cookie(同时ajax请求中也必须打开withCredentials属性)
- Access-Control-Expose-Headers:需要的其他header字段
-
预检请求响应头:
- Access-Control-Allow-Methods
- Access-Control-Allow-Headers
- Access-Control-Allow-Credentials
- Access-Control-Max-Age
-
优点: 基于 HTTP 标准。
-
缺点: 存在兼容问题,支持 IE 10 以上。
postMessage
- 通过嵌入 iframe 加载目标 origin,使用 postMessage() 和监听 message 事件实现数据通信。
- 父页面=>子页面传数据:父页面调用postmessage,
iframe.contentWindow.postMessgae(JSON.stringify(data), 'http://www.domain2.com'),子页面监听message事件:window.addEventListener('message', function(e) { console.log(e.data) } - 子页面=>父页面传数据:子页面调用postmessage,
window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');,父页面监听message事件
iframe + location.hash
- 通过修改 location.hash 和监听 hashchange 事件实现数据通信。
- 父页面=>子页面传数据:可以直接修改iframe.src,在后面把要传输的数据通过哈希的方式拼接在URL后面,子页面监听hashChange,获取数据
- 子页面=>父页面传数据:因为域不同,所以无法在子页面直接修改父页面的hash,这时候需要第三个页面——父页面同域的代理页面,内嵌在子页面里,去修改最外层父页面的hash:
parent.parent.location.hash = self.location.hash... - 缺点: 数据直接暴露在了 url 中;数据类型和大小受限。
iframe + window.name
- 利用window.name属性的独特之处:name值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)
- 通过iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域
iframe + document.domain
- 通过将父子页面的document.domain均设置为它们的父域来实现iframe内部元素的获取
- 缺点:这种方法只适用于不同子域的框架间的交互
WebSocket
- 什么是websocket
- 一个基于TCP连接的持久化网络通信协议
- 服务端可以主动推送信息给客户端,不需要客户端重复的向服务端发请求查询
- webSocket与传统的http有什么优势
- 客户端与服务器只需要一个TCP连接,比http长轮询更少
- 服务端可以推送数据到客户端
- 更轻量的协议头,减少数据传输量
Server Proxy
nginx 反向代理
CSRF和XSS
CSRF : Cross-Site Request Forgery 跨站请求伪造 CORS : Cross Origin Resourse-Sharing 跨站资源共享 XSS : Cross Site Scrit 跨站脚本攻击
CSRF
内容:
- 拿着用户的cookie去获取浏览器信任
防御手段:
- 验证码
- Referer Check
- Token 验证
XSS
内容:
- 来自用户的 UGC 信息
- 来自第三方的链接
- URL 参数
- POST 参数
- Referer (可能来自不可信的来源)
- Cookie (可能来自其他子域注入)
防御手段:
- HttpOnly 防止劫取 Cookie
- 用户的输入检查
- 服务端的输出检查
关于Serverless
- 定义:Serverless 不是具体的一个编程框架、类库或者工具。简单来说,Serverless 是一种软件系统架构思想和方法,它的核心思想是用户无须关注支撑应用服务运行的底层服务器的状态、资源(比如 CPU、内存、磁盘及网络)及数量
关于设计模式
使用设计模式是为了重用代码,使代码更好理解和维护,保证代码的可靠性。使代码真正工程化
常见的设计模式:
- 创建型:单例模式,原型模式,工厂模式,适配器模式
- 结构型:装饰器模式,代理模式
- 行为型:观察者模式,迭代器模式
具体解释:
- 工厂模式【jquery】:定义一个用于创建对象的接口,这个接口由子类决定实例化哪一个类。该模式使一个类的实例化延迟到了子类。而子类可以重写接口方法以便创建的时候指定自己的对象类型
- 单例模式【redux的store】:一个类只有一个实例,并提供一个访问它的全局访问点。
- 适配器模式【整合第三方SDK,封装旧接口,computed】:将一个类的接口转化为另外一个接口,使类之间接口不兼容问题通过适配器解决
- 装饰者模式【ES7decorator装饰器】在不改变原对象的基础上,对原对象进行包装,给他添加一些其他属性或方法——装饰类和被装饰类都只关心自身的核心业务,实现了解耦
- 代理模式【ES6 Proxy】
- 观察者模式【vue响应式】当一个对象的改变需要同时改变其它对象,并且它不知道具体有多少对象需要改变的时候,就应该考虑使用观察者模式
- 原型模式【继承】创建一个共享的原型,通过拷贝这个原型来创建新的类
GraphQL优缺点
优点:
- 按需获取。客户端可以按自己的需要,从服务端获取已经定义好的资源和数据,而非进行与服务端BFF相关的编程。
- 代码即文档。与参数相比,GraphQL编写的查询语句更像是一份文档。换句话说,它适合于人类阅读。
- 易于使用的API调试工具。多数的GraphQL实现都能提供一个开发用的前端调试API界面,可以进行API请求、验证等。
- 强类型的API检查。面向前端的接口都有强类型的Schema做保证,能快速地定位问题。
- 易于版本化的API。其可以通过Schema扩展API,而REST则需要通过URI或HTTPheader等来接收版本。
缺点:
- HTTP请求无法被缓存。由于所有HTTP的请求只能在App级别上实现缓存,即通过GraphQL客户端库来实现
- 错误码处理不友好。GraphQL统一返回200的结果,在其中对错误信息进行包装。对于传统的HTTP客户端来说,需要额外的处理才能走到异常分支。
该用gql还是BFF呢? 答:如果业务一直在变动,或者需要对外提供API,选择GraphQL更合适。而如果业务变动不频繁,或者客户端数据量少(如只有Web),那么使用BFF也可以
微前端如何实施?
What?
- 把单页面前端应用由单体应用变成 由多个小型前端应用聚合这一起的应用
- 各个前端应用还可以独立开发、独立部署
- 同时,他们还可以并行开发——通过npm git submodule
Why?
- 应用自治,单一职责,独立开发部署,提升开发效率
- 技术栈无关
- 遗留系统迁移
How?
- 路由分发式。通过HTTP服务器的反向代理功能,将请求路由到对应的应用上。
- 前端微服务化。在不同的框架之上设计通信和加载机制,以在一个页面内加载对应的应用。
- 微应用。通过软件工程的方式,在部署构建环境中,把多个独立的应用组合成一个单体应用。
- 微件化。开发一个新的构建系统,将部分业务功能构建成一个独立的chunk代码,使用时只需要远程加载即可。
- 前端容器化。将iframe作为容器来容纳其他前端应用。
- 应用组件化。借助于WebComponents技术,来构建跨框架的前端应用。实施的方式虽然多,但都是依据场景而采用的。在有些场景下,可能没有合适的方式;在有些场景下,则可以同时使用多种方案。