写点什么

20 道前端高频面试题(附答案)

作者:loveX001
  • 2022-11-10
    浙江
  • 本文字数:19395 字

    阅读完需:约 64 分钟

line-height 的理解及其赋值方式

(1)line-height 的概念:


  • line-height 指一行文本的高度,包含了字间距,实际上是下一行基线到上一行基线距离;

  • 如果一个标签没有定义 height 属性,那么其最终表现的高度由 line-height 决定;

  • 一个容器没有设置高度,那么撑开容器高度的是 line-height,而不是容器内的文本内容;

  • 把 line-height 值设置为 height 一样大小的值可以实现单行文字的垂直居中;

  • line-height 和 height 都能撑开一个高度;


(2)line-height 的赋值方式:


  • 带单位:px 是固定值,而 em 会参考父元素 font-size 值计算自身的行高

  • 纯数字:会把比例传递给后代。例如,父级行高为 1.5,子元素字体为 18px,则子元素行高为 1.5 * 18 = 27px

  • 百分比:将计算后的值传递给后代

async/await 的优势

单一的 Promise 链并不能发现 async/await 的优势,但是,如果需要处理由多个 Promise 组成的 then 链的时候,优势就能体现出来了(很有意思,Promise 通过 then 链来解决多层回调的问题,现在又用 async/await 来进一步优化它)。


假设一个业务,分多个步骤完成,每个步骤都是异步的,而且依赖于上一个步骤的结果。仍然用 setTimeout 来模拟异步操作:


/** * 传入参数 n,表示这个函数执行的时间(毫秒) * 执行的结果是 n + 200,这个值将用于下一步骤 */function takeLongTime(n) {    return new Promise(resolve => {        setTimeout(() => resolve(n + 200), n);    });}function step1(n) {    console.log(`step1 with ${n}`);    return takeLongTime(n);}function step2(n) {    console.log(`step2 with ${n}`);    return takeLongTime(n);}function step3(n) {    console.log(`step3 with ${n}`);    return takeLongTime(n);}
复制代码


现在用 Promise 方式来实现这三个步骤的处理:


function doIt() {    console.time("doIt");    const time1 = 300;    step1(time1)        .then(time2 => step2(time2))        .then(time3 => step3(time3))        .then(result => {            console.log(`result is ${result}`);            console.timeEnd("doIt");        });}doIt();// c:\var\test>node --harmony_async_await .// step1 with 300// step2 with 500// step3 with 700// result is 900// doIt: 1507.251ms
复制代码


输出结果 resultstep3() 的参数 700 + 200 = 900doIt() 顺序执行了三个步骤,一共用了 300 + 500 + 700 = 1500 毫秒,和 console.time()/console.timeEnd() 计算的结果一致。


如果用 async/await 来实现呢,会是这样:


async function doIt() {    console.time("doIt");    const time1 = 300;    const time2 = await step1(time1);    const time3 = await step2(time2);    const result = await step3(time3);    console.log(`result is ${result}`);    console.timeEnd("doIt");}doIt();
复制代码


结果和之前的 Promise 实现是一样的,但是这个代码看起来是不是清晰得多,几乎跟同步代码一样

其他值到字符串的转换规则?

  • Null 和 Undefined 类型 ,null 转换为 "null",undefined 转换为 "undefined",

  • Boolean 类型,true 转换为 "true",false 转换为 "false"。

  • Number 类型的值直接转换,不过那些极小和极大的数字会使用指数形式。

  • Symbol 类型的值直接转换,但是只允许显式强制类型转换,使用隐式强制类型转换会产生错误。

  • 对普通对象来说,除非自行定义 toString() 方法,否则会调用 toString()(Object.prototype.toString())来返回内部属性 [[Class]] 的值,如"[object Object]"。如果对象有自己的 toString() 方法,字符串化时就会调用该方法并使用其返回值。

介绍一下 HTTPS 和 HTTP 区别

HTTPS 要比 HTTPS 多了 secure 安全性这个概念,实际上, HTTPS 并不是一个新的应用层协议,它其实就是 HTTP + TLS/SSL 协议组合而成,而安全性的保证正是 SSL/TLS 所做的工作。


SSL


安全套接层(Secure Sockets Layer)


TLS


(传输层安全,Transport Layer Security)


现在主流的版本是 TLS/1.2, 之前的 TLS1.0、TLS1.1 都被认为是不安全的,在不久的将来会被完全淘汰。


HTTPS 就是身披了一层 SSL 的 HTTP



那么区别有哪些呢👇


  • HTTP 是明文传输协议,HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。

  • HTTPS 比 HTTP 更加安全,对搜索引擎更友好,利于 SEO,谷歌、百度优先索引 HTTPS 网页。

  • HTTPS 标准端口 443,HTTP 标准端口 80。

  • HTTPS 需要用到 SSL 证书,而 HTTP 不用。


我觉得记住以下两点 HTTPS 主要作用就行👇


  1. 对数据进行加密,并建立一个信息安全通道,来保证传输过程中的数据安全;

  2. 对网站服务器进行真实身份认证。


HTTPS 的缺点


  • 证书费用以及更新维护。

  • HTTPS 降低一定用户访问速度(实际上优化好就不是缺点了)。

  • HTTPS 消耗 CPU 资源,需要增加大量机器。


参考:前端进阶面试题详细解答

TCP 和 UDP 的区别

Promise

这里你谈 promise的时候,除了将他解决的痛点以及常用的 API 之外,最好进行拓展把 eventloop 带进来好好讲一下,microtask(微任务)、macrotask(任务) 的执行顺序,如果看过 promise 源码,最好可以谈一谈 原生 Promise 是如何实现的。Promise 的关键点在于callback 的两个参数,一个是 resovle,一个是 reject。还有就是 Promise 的链式调用(Promise.then(),每一个 then 都是一个责任人)


  • PromiseES6 新增的语法,解决了回调地狱的问题。

  • 可以把 Promise看成一个状态机。初始是 pending 状态,可以通过函数 resolvereject,将状态转变为 resolved 或者 rejected 状态,状态一旦改变就不能再次变化。

  • then 函数会返回一个 Promise 实例,并且该返回值是一个新的实例而不是之前的实例。因为 Promise 规范规定除了 pending 状态,其他状态是不可以改变的,如果返回的是一个相同实例的话,多个 then 调用就失去意义了。 对于 then 来说,本质上可以把它看成是 flatMap


1. Promise 的基本情况


简单来说它就是一个容器,里面保存着某个未来才会结束的事件(通常是异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息


一般 Promise 在执行过程中,必然会处于以下几种状态之一。


  • 待定(pending):初始状态,既没有被完成,也没有被拒绝。

  • 已完成(fulfilled):操作成功完成。

  • 已拒绝(rejected):操作失败。


待定状态的 Promise 对象执行的话,最后要么会通过一个值完成,要么会通过一个原因被拒绝。当其中一种情况发生时,我们用 Promisethen 方法排列起来的相关处理程序就会被调用。因为最后 Promise.prototype.thenPromise.prototype.catch 方法返回的是一个 Promise, 所以它们可以继续被链式调用


关于 Promise 的状态流转情况,有一点值得注意的是,内部状态改变之后不可逆,你需要在编程过程中加以注意。文字描述比较晦涩,我们直接通过一张图就能很清晰地看出 Promise 内部状态流转的情况



从上图可以看出,我们最开始创建一个新的 Promise 返回给 p1 ,然后开始执行,状态是 pending,当执行 resolve之后状态就切换为 fulfilled,执行 reject 之后就变为 rejected 的状态


2. Promise 的静态方法


  • all 方法

  • 语法: Promise.all(iterable)

  • 参数: 一个可迭代对象,如 Array

  • 描述: 此方法对于汇总多个 promise 的结果很有用,在 ES6 中可以将多个 Promise.all 异步请求并行操作,返回结果一般有下面两种情况。

  • 当所有结果成功返回时按照请求顺序返回成功结果。

  • 当其中有一个失败方法时,则进入失败方法

  • 我们来看下业务的场景,对于下面这个业务场景页面的加载,将多个请求合并到一起,用 all 来实现可能效果会更好,请看代码片段


// 在一个页面中需要加载获取轮播列表、获取店铺列表、获取分类列表这三个操作,页面需要同时发出请求进行页面渲染,这样用 `Promise.all` 来实现,看起来更清晰、一目了然。

//1.获取轮播数据列表function getBannerList(){ return new Promise((resolve,reject)=>{ setTimeout(function(){ resolve('轮播数据') },300) })}//2.获取店铺列表function getStoreList(){ return new Promise((resolve,reject)=>{ setTimeout(function(){ resolve('店铺数据') },500) })}//3.获取分类列表function getCategoryList(){ return new Promise((resolve,reject)=>{ setTimeout(function(){ resolve('分类数据') },700) })}function initLoad(){ Promise.all([getBannerList(),getStoreList(),getCategoryList()]) .then(res=>{ console.log(res) }).catch(err=>{ console.log(err) })} initLoad()
复制代码


  • allSettled 方法

  • Promise.allSettled 的语法及参数跟 Promise.all 类似,其参数接受一个 Promise 的数组,返回一个新的 Promise唯一的不同在于,执行完之后不会失败,也就是说当 Promise.allSettled 全部处理完成后,我们可以拿到每个 Promise 的状态,而不管其是否处理成功

  • 我们来看一下用 allSettled 实现的一段代码


const resolved = Promise.resolve(2);const rejected = Promise.reject(-1);const allSettledPromise = Promise.allSettled([resolved, rejected]);allSettledPromise.then(function (results) {  console.log(results);});// 返回结果:// [//    { status: 'fulfilled', value: 2 },//    { status: 'rejected', reason: -1 }// ]
复制代码


从上面代码中可以看到,Promise.allSettled 最后返回的是一个数组,记录传进来的参数中每个 Promise 的返回值,这就是和 all 方法不太一样的地方。


  • any 方法

  • 语法: Promise.any(iterable)

  • 参数: iterable 可迭代的对象,例如 Array

  • 描述: any 方法返回一个 Promise,只要参数 Promise 实例有一个变成 fulfilled状态,最后 any返回的实例就会变成 fulfilled 状态;如果所有参数 Promise 实例都变成 rejected 状态,包装实例就会变成 rejected 状态。


const resolved = Promise.resolve(2);const rejected = Promise.reject(-1);const anyPromise = Promise.any([resolved, rejected]);anyPromise.then(function (results) {  console.log(results);});// 返回结果:// 2
复制代码


从改造后的代码中可以看出,只要其中一个 Promise 变成 fulfilled状态,那么 any 最后就返回这个p romise。由于上面 resolved 这个 Promise 已经是 resolve 的了,故最后返回结果为 2


  • race 方法

  • 语法: Promise.race(iterable)

  • 参数: iterable 可迭代的对象,例如 Array

  • 描述: race方法返回一个 Promise,只要参数的 Promise 之中有一个实例率先改变状态,则 race 方法的返回状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给 race 方法的回调函数

  • 我们来看一下这个业务场景,对于图片的加载,特别适合用 race 方法来解决,将图片请求和超时判断放到一起,用 race 来实现图片的超时判断。请看代码片段。


//请求某个图片资源function requestImg(){  var p = new Promise(function(resolve, reject){    var img = new Image();    img.onload = function(){ resolve(img); }    img.src = 'http://www.baidu.com/img/flexible/logo/pc/result.png';  });  return p;}//延时函数,用于给请求计时function timeout(){  var p = new Promise(function(resolve, reject){    setTimeout(function(){ reject('图片请求超时'); }, 5000);  });  return p;}Promise.race([requestImg(), timeout()]).then(function(results){  console.log(results);}).catch(function(reason){  console.log(reason);});

// 从上面的代码中可以看出,采用 Promise 的方式来判断图片是否加载成功,也是针对 Promise.race 方法的一个比较好的业务场景
复制代码



promise 手写实现,面试够用版:


function myPromise(constructor){    let self=this;    self.status="pending" //定义状态改变前的初始状态    self.value=undefined;//定义状态为resolved的时候的状态    self.reason=undefined;//定义状态为rejected的时候的状态    function resolve(value){        //两个==="pending",保证了状态的改变是不可逆的       if(self.status==="pending"){          self.value=value;          self.status="resolved";       }    }    function reject(reason){        //两个==="pending",保证了状态的改变是不可逆的       if(self.status==="pending"){          self.reason=reason;          self.status="rejected";       }    }    //捕获构造异常    try{       constructor(resolve,reject);    }catch(e){       reject(e);    }}// 定义链式调用的then方法myPromise.prototype.then=function(onFullfilled,onRejected){   let self=this;   switch(self.status){      case "resolved":        onFullfilled(self.value);        break;      case "rejected":        onRejected(self.reason);        break;      default:          }}
复制代码

async/await

Generator 函数的语法糖。有更好的语义、更好的适用性、返回值是 Promise


  • await 和 promise 一样,更多的是考笔试题,当然偶尔也会问到和 promise 的一些区别。

  • await 相比直接使用 Promise 来说,优势在于处理 then 的调用链,能够更清晰准确的写出代码。缺点在于滥用 await 可能会导致性能问题,因为 await 会阻塞代码,也许之后的异步代码并不依赖于前者,但仍然需要等待前者完成,导致代码失去了并发性,此时更应该使用 Promise.all。

  • 一个函数如果加上 async ,那么该函数就会返回一个 Promise


  • async => *

  • await => yield


// 基本用法
async function timeout (ms) { await new Promise((resolve) => { setTimeout(resolve, ms) })}async function asyncConsole (value, ms) { await timeout(ms) console.log(value)}asyncConsole('hello async and await', 1000)
复制代码


下面来看一个使用 await 的代码。


var a = 0var b = async () => {  a = a + await 10  console.log('2', a) // -> '2' 10  a = (await 10) + a  console.log('3', a) // -> '3' 20}b()a++console.log('1', a) // -> '1' 1
复制代码


  • 首先函数b 先执行,在执行到 await 10 之前变量 a 还是 0,因为在 await 内部实现了 generatorsgenerators 会保留堆栈中东西,所以这时候 a = 0 被保存了下来

  • 因为 await 是异步操作,遇到await就会立即返回一个pending状态的Promise对象,暂时返回执行代码的控制权,使得函数外的代码得以继续执行,所以会先执行 console.log('1', a)

  • 这时候同步代码执行完毕,开始执行异步代码,将保存下来的值拿出来使用,这时候 a = 10

  • 然后后面就是常规执行代码了


优缺点:


async/await的优势在于处理 then 的调用链,能够更清晰准确的写出代码,并且也能优雅地解决回调地狱问题。当然也存在一些缺点,因为 await 将异步代码改造成了同步代码,如果多个异步代码没有依赖性却使用了 await 会导致性能上的降低。


async 原理


async/await语法糖就是使用Generator函数+自动执行器来运作的


// 定义了一个promise,用来模拟异步请求,作用是传入参数++function getNum(num){    return new Promise((resolve, reject) => {        setTimeout(() => {            resolve(num+1)        }, 1000)    })}
//自动执行器,如果一个Generator函数没有执行完,则递归调用function asyncFun(func){ var gen = func();
function next(data){ var result = gen.next(data); if (result.done) return result.value; result.value.then(function(data){ next(data); }); }
next();}
// 所需要执行的Generator函数,内部的数据在执行完成一步的promise之后,再调用下一步var func = function* (){ var f1 = yield getNum(1); var f2 = yield getNum(f1); console.log(f2) ;};asyncFun(func);
复制代码


  • 在执行的过程中,判断一个函数的promise是否完成,如果已经完成,将结果传入下一个函数,继续重复此步骤

  • 每一个 next() 方法返回值的 value 属性为一个 Promise 对象,所以我们为其添加 then 方法, 在 then 方法里面接着运行 next 方法挪移遍历器指针,直到 Generator函数运行完成


浏览器

浏览器架构

单进程浏览器时代


单进程浏览器是指浏览器的所有功能模块都是运行在同一个进程里,这些模块包含了网络、插件、JavaScript 运行环境、渲染引擎和页面等。其实早在 2007 年之前,市面上浏览器都是单进程的



  • 缺点

  • 不稳定:一个插件的意外崩溃会引起整个浏览器的崩溃

  • 不流畅:所有页面的渲染模块、JavaScript 执行环境以及插件都是运行在同一个线程中的,这就意味着同一时刻只能有一个模块可以执行

  • 不安全:可以通过浏览器的漏洞来获取系统权限,这些脚本获取系统权限之后也可以对你的电脑做一些恶意的事情,同样也会引发安全问题

  • 以上这些就是当时浏览器的特点,不稳定,不流畅,而且不安全


多进程浏览器时代


  • 由于进程是相互隔离的,所以当一个页面或者插件崩溃时,影响到的仅仅是当前的页面进程或者插件进程,并不会影响到浏览器和其他页面,这就完美地解决了页面或者插件的崩溃会导致整个浏览器崩溃,也就是不稳定的问题

  • JavaScript 也是运行在渲染进程中的,所以即使 JavaScript 阻塞了渲染进程,影响到的也只是当前的渲染页面,而并不会影响浏览器和其他页面,因为其他页面的脚本是运行在它们自己的渲染进程中的

  • Chrome 把插件进程和渲染进程锁在沙箱里面,这样即使在渲染进程或者插件进程里面执行了恶意程序,恶意程序也无法突破沙箱去获取系统权限。



最新的 Chrome 浏览器包括:1个浏览器(Browser)主进程1个 GPU 进程1个网络(NetWork)进程多个渲染进程多个插件进程


  • 浏览器进程 。主要负责界面显示、用户交互、子进程管理,同时提供存储等功能。

  • 渲染进程 。核心任务是将 HTML、CSS 和 JavaScript 转换为用户可以与之交互的网页,排版引擎 Blink 和 JavaScript 引擎 V8 都是运行在该进程中,默认情况下,Chrome 会为每个 Tab 标签创建一个渲染进程。出于安全考虑,渲染进程都是运行在沙箱模式下。

  • GPU 进程 。其实,Chrome 刚开始发布的时候是没有 GPU 进程的。而 GPU 的使用初衷是为了实现 3D CSS 的效果,只是随后网页、Chrome 的 UI 界面都选择采用 GPU 来绘制,这使得 GPU 成为浏览器普遍的需求。最后,Chrome 在其多进程架构上也引入了 GPU 进程。

  • 网络进程 。主要负责页面的网络资源加载,之前是作为一个模块运行在浏览器进程里面的,直至最近才独立出来,成为一个单独的进程。

  • 插件进程 。主要是负责插件的运行,因插件易崩溃,所以需要通过插件进程来隔离,以保证插件进程崩溃不会对浏览器和页面造成影响

HTTP 状态码

状态码的类别:


1. 2XX (Success 成功状态码)

状态码 2XX 表示请求被正常处理了。

(1)200 OK

200 OK 表示客户端发来的请求被服务器端正常处理了。

(2)204 No Content

该状态码表示客户端发送的请求已经在服务器端正常处理了,但是没有返回的内容,响应报文中不包含实体的主体部分。一般在只需要从客户端往服务器端发送信息,而服务器端不需要往客户端发送内容时使用。

(3)206 Partial Content

该状态码表示客户端进行了范围请求,而服务器端执行了这部分的 GET 请求。响应报文中包含由 Content-Range 指定范围的实体内容。

2. 3XX (Redirection 重定向状态码)

3XX 响应结果表明浏览器需要执行某些特殊的处理以正确处理请求。

(1)301 Moved Permanently

永久重定向。 该状态码表示请求的资源已经被分配了新的 URI,以后应使用资源指定的 URI。新的 URI 会在 HTTP 响应头中的 Location 首部字段指定。若用户已经把原来的 URI 保存为书签,此时会按照 Location 中新的 URI 重新保存该书签。同时,搜索引擎在抓取新内容的同时也将旧的网址替换为重定向之后的网址。


使用场景:


  • 当我们想换个域名,旧的域名不再使用时,用户访问旧域名时用 301 就重定向到新的域名。其实也是告诉搜索引擎收录的域名需要对新的域名进行收录。

  • 在搜索引擎的搜索结果中出现了不带 www 的域名,而带 www 的域名却没有收录,这个时候可以用 301 重定向来告诉搜索引擎我们目标的域名是哪一个。

(2)302 Found

临时重定向。 该状态码表示请求的资源被分配到了新的 URI,希望用户(本次)能使用新的 URI 访问资源。和 301 Moved Permanently 状态码相似,但是 302 代表的资源不是被永久重定向,只是临时性质的。也就是说已移动的资源对应的 URI 将来还有可能发生改变。若用户把 URI 保存成书签,但不会像 301 状态码出现时那样去更新书签,而是仍旧保留返回 302 状态码的页面对应的 URI。同时,搜索引擎会抓取新的内容而保留旧的网址。因为服务器返回 302 代码,搜索引擎认为新的网址只是暂时的。


使用场景:


  • 当我们在做活动时,登录到首页自动重定向,进入活动页面。

  • 未登陆的用户访问用户中心重定向到登录页面。

  • 访问 404 页面重新定向到首页。

(3)303 See Other

该状态码表示由于请求对应的资源存在着另一个 URI,应使用 GET 方法定向获取请求的资源。303 状态码和 302 Found 状态码有着相似的功能,但是 303 状态码明确表示客户端应当采用 GET 方法获取资源。


303 状态码通常作为 PUT 或 POST 操作的返回结果,它表示重定向链接指向的不是新上传的资源,而是另外一个页面,比如消息确认页面或上传进度页面。而请求重定向页面的方法要总是使用 GET。


注意:


  • 当 301、302、303 响应状态码返回时,几乎所有的浏览器都会把 POST 改成 GET,并删除请求报文内的主体,之后请求会再次自动发送。

  • 301、302 标准是禁止将 POST 方法变成 GET 方法的,但实际大家都会这么做。

(4)304 Not Modified

浏览器缓存相关。 该状态码表示客户端发送附带条件的请求时,服务器端允许请求访问资源,但未满足条件的情况。304 状态码返回时,不包含任何响应的主体部分。304 虽然被划分在 3XX 类别中,但是和重定向没有关系。


带条件的请求(Http 条件请求):使用 Get 方法 请求,请求报文中包含(if-matchif-none-matchif-modified-sinceif-unmodified-sinceif-range)中任意首部。


状态码 304 并不是一种错误,而是告诉客户端有缓存,直接使用缓存中的数据。返回页面的只有头部信息,是没有内容部分的,这样在一定程度上提高了网页的性能。

(5)307 Temporary Redirect

307 表示临时重定向。 该状态码与 302 Found 有着相同含义,尽管 302 标准禁止 POST 变成 GET,但是实际使用时还是这样做了。


307 会遵守浏览器标准,不会从 POST 变成 GET。但是对于处理请求的行为时,不同浏览器还是会出现不同的情况。规范要求浏览器继续向 Location 的地址 POST 内容。规范要求浏览器继续向 Location 的地址 POST 内容。

3. 4XX (Client Error 客户端错误状态码)

4XX 的响应结果表明客户端是发生错误的原因所在。

(1)400 Bad Request

该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。另外,浏览器会像 200 OK 一样对待该状态码。

(2)401 Unauthorized

该状态码表示发送的请求需要有通过 HTTP 认证(BASIC 认证、DIGEST 认证)的认证信息。若之前已进行过一次请求,则表示用户认证失败


返回含有 401 的响应必须包含一个适用于被请求资源的 WWW-Authenticate 首部用以质询(challenge)用户信息。当浏览器初次接收到 401 响应,会弹出认证用的对话窗口。


以下情况会出现 401:


  • 401.1 - 登录失败。

  • 401.2 - 服务器配置导致登录失败。

  • 401.3 - 由于 ACL 对资源的限制而未获得授权。

  • 401.4 - 筛选器授权失败。

  • 401.5 - ISAPI/CGI 应用程序授权失败。

  • 401.7 - 访问被 Web 服务器上的 URL 授权策略拒绝。这个错误代码为 IIS 6.0 所专用。

(3)403 Forbidden

该状态码表明请求资源的访问被服务器拒绝了,服务器端没有必要给出详细理由,但是可以在响应报文实体的主体中进行说明。进入该状态后,不能再继续进行验证。该访问是永久禁止的,并且与应用逻辑密切相关。


IIS 定义了许多不同的 403 错误,它们指明更为具体的错误原因:


  • 403.1 - 执行访问被禁止。

  • 403.2 - 读访问被禁止。

  • 403.3 - 写访问被禁止。

  • 403.4 - 要求 SSL。

  • 403.5 - 要求 SSL 128。

  • 403.6 - IP 地址被拒绝。

  • 403.7 - 要求客户端证书。

  • 403.8 - 站点访问被拒绝。

  • 403.9 - 用户数过多。

  • 403.10 - 配置无效。

  • 403.11 - 密码更改。

  • 403.12 - 拒绝访问映射表。

  • 403.13 - 客户端证书被吊销。

  • 403.14 - 拒绝目录列表。

  • 403.15 - 超出客户端访问许可。

  • 403.16 - 客户端证书不受信任或无效。

  • 403.17 - 客户端证书已过期或尚未生效

  • 403.18 - 在当前的应用程序池中不能执行所请求的 URL。这个错误代码为 IIS 6.0 所专用。

  • 403.19 - 不能为这个应用程序池中的客户端执行 CGI。这个错误代码为 IIS 6.0 所专用。

  • 403.20 - Passport 登录失败。这个错误代码为 IIS 6.0 所专用。

(4)404 Not Found

该状态码表明服务器上无法找到请求的资源。除此之外,也可以在服务器端拒绝请求且不想说明理由时使用。以下情况会出现 404:


  • 404.0 -(无) – 没有找到文件或目录。

  • 404.1 - 无法在所请求的端口上访问 Web 站点。

  • 404.2 - Web 服务扩展锁定策略阻止本请求。

  • 404.3 - MIME 映射策略阻止本请求。

(5)405 Method Not Allowed

该状态码表示客户端请求的方法虽然能被服务器识别,但是服务器禁止使用该方法。GET 和 HEAD 方法,服务器应该总是允许客户端进行访问。客户端可以通过 OPTIONS 方法(预检)来查看服务器允许的访问方法, 如下


Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
复制代码

4. 5XX (Server Error 服务器错误状态码)

5XX 的响应结果表明服务器本身发生错误.

(1)500 Internal Server Error

该状态码表明服务器端在执行请求时发生了错误。也有可能是 Web 应用存在的 bug 或某些临时的故障。

(2)502 Bad Gateway

该状态码表明扮演网关或代理角色的服务器,从上游服务器中接收到的响应是无效的。注意,502 错误通常不是客户端能够修复的,而是需要由途经的 Web 服务器或者代理服务器对其进行修复。以下情况会出现 502:


  • 502.1 - CGI (通用网关接口)应用程序超时。

  • 502.2 - CGI (通用网关接口)应用程序出错。

(3)503 Service Unavailable

该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。如果事先得知解除以上状况需要的时间,最好写入 RetryAfter 首部字段再返回给客户端。


使用场景:


  • 服务器停机维护时,主动用 503 响应请求;

  • nginx 设置限速,超过限速,会返回 503。

(4)504 Gateway Timeout

该状态码表示网关或者代理的服务器无法在规定的时间内获得想要的响应。他是 HTTP 1.1 中新加入的。


使用场景:代码执行时间超时,或者发生了死循环。

5. 总结

(1)2XX 成功


  • 200 OK,表示从客户端发来的请求在服务器端被正确处理

  • 204 No content,表示请求成功,但响应报文不含实体的主体部分

  • 205 Reset Content,表示请求成功,但响应报文不含实体的主体部分,但是与 204 响应不同在于要求请求方重置内容

  • 206 Partial Content,进行范围请求


(2)3XX 重定向


  • 301 moved permanently,永久性重定向,表示资源已被分配了新的 URL

  • 302 found,临时性重定向,表示资源临时被分配了新的 URL

  • 303 see other,表示资源存在着另一个 URL,应使用 GET 方法获取资源

  • 304 not modified,表示服务器允许访问资源,但因发生请求未满足条件的情况

  • 307 temporary redirect,临时重定向,和 302 含义类似,但是期望客户端保持请求方法不变向新的地址发出请求


(3)4XX 客户端错误


  • 400 bad request,请求报文存在语法错误

  • 401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息

  • 403 forbidden,表示对请求资源的访问被服务器拒绝

  • 404 not found,表示在服务器上没有找到请求的资源


(4)5XX 服务器错误


  • 500 internal sever error,表示服务器端在执行请求时发生了错误

  • 501 Not Implemented,表示服务器不支持当前请求所需要的某个功能

  • 503 service unavailable,表明服务器暂时处于超负载或正在停机维护,无法处理请求

TCP 的重传机制

由于 TCP 的下层网络(网络层)可能出现丢失、重复或失序的情况,TCP 协议提供可靠数据传输服务。为保证数据传输的正确性,TCP 会重传其认为已丢失(包括报文中的比特错误)的包。TCP 使用两套独立的机制来完成重传,一是基于时间,二是基于确认信息


TCP 在发送一个数据之后,就开启一个定时器,若是在这个时间内没有收到发送数据的 ACK 确认报文,则对该报文进行重传,在达到一定次数还没有成功时放弃并发送一个复位信号。

代码输出结果

function Person(name) {    this.name = name}var p2 = new Person('king');console.log(p2.__proto__) //Person.prototypeconsole.log(p2.__proto__.__proto__) //Object.prototypeconsole.log(p2.__proto__.__proto__.__proto__) // nullconsole.log(p2.__proto__.__proto__.__proto__.__proto__)//null后面没有了,报错console.log(p2.__proto__.__proto__.__proto__.__proto__.__proto__)//null后面没有了,报错console.log(p2.constructor)//Personconsole.log(p2.prototype)//undefined p2是实例,没有prototype属性console.log(Person.constructor)//Function 一个空函数console.log(Person.prototype)//打印出Person.prototype这个对象里所有的方法和属性console.log(Person.prototype.constructor)//Personconsole.log(Person.prototype.__proto__)// Object.prototypeconsole.log(Person.__proto__) //Function.prototypeconsole.log(Function.prototype.__proto__)//Object.prototypeconsole.log(Function.__proto__)//Function.prototypeconsole.log(Object.__proto__)//Function.prototypeconsole.log(Object.prototype.__proto__)//null
复制代码


这道义题目考察原型、原型链的基础,记住就可以了。

快排--时间复杂度 nlogn~ n^2 之间

题目描述:实现一个快排


实现代码如下:


function quickSort(arr) {  if (arr.length < 2) {    return arr;  }  const cur = arr[arr.length - 1];  const left = arr.filter((v, i) => v <= cur && i !== arr.length - 1);  const right = arr.filter((v) => v > cur);  return [...quickSort(left), cur, ...quickSort(right)];}// console.log(quickSort([3, 6, 2, 4, 1]));
复制代码

Ajax

它是一种异步通信的方法,通过直接由 js 脚本向服务器发起 http 通信,然后根据服务器返回的数据,更新网页的相应部分,而不用刷新整个页面的一种方法。



面试手写(原生):


//1:创建Ajax对象var xhr = window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');// 兼容IE6及以下版本//2:配置 Ajax请求地址xhr.open('get','index.xml',true);//3:发送请求xhr.send(null); // 严谨写法//4:监听请求,接受响应xhr.onreadysatechange=function(){     if(xhr.readySate==4&&xhr.status==200 || xhr.status==304 )          console.log(xhr.responsetXML)}
复制代码


jQuery 写法


$.ajax({  type:'post',  url:'',  async:ture,//async 异步  sync  同步  data:data,//针对post请求  dataType:'jsonp',  success:function (msg) {
}, error:function (error) {
}})
复制代码


promise 封装实现:


// promise 封装实现:
function getJSON(url) { // 创建一个 promise 对象 let promise = new Promise(function(resolve, reject) { let xhr = new XMLHttpRequest();
// 新建一个 http 请求 xhr.open("GET", url, true);
// 设置状态的监听函数 xhr.onreadystatechange = function() { if (this.readyState !== 4) return;
// 当请求成功或失败时,改变 promise 的状态 if (this.status === 200) { resolve(this.response); } else { reject(new Error(this.statusText)); } };
// 设置错误监听函数 xhr.onerror = function() { reject(new Error(this.statusText)); };
// 设置响应的数据类型 xhr.responseType = "json";
// 设置请求头信息 xhr.setRequestHeader("Accept", "application/json");
// 发送 http 请求 xhr.send(null); });
return promise;}
复制代码

PWA 使用过吗?serviceWorker 的使用原理是啥?

渐进式网络应用(PWA)是谷歌在 2015 年底提出的概念。基本上算是 web 应用程序,但在外观和感觉上与原生app类似。支持PWA的网站可以提供脱机工作、推送通知和设备硬件访问等功能。


Service Worker是浏览器在后台独立于网页运行的脚本,它打开了通向不需要网页或用户交互的功能的大门。 现在,它们已包括如推送通知和后台同步等功能。 将来,Service Worker将会支持如定期同步或地理围栏等其他功能。 本教程讨论的核心功能是拦截和处理网络请求,包括通过程序来管理缓存中的响应。

setTimeout 模拟 setInterval

描述:使用setTimeout模拟实现setInterval的功能。


实现


const mySetInterval(fn, time) {    let timer = null;    const interval = () => {        timer = setTimeout(() => {            fn();  // time 时间之后会执行真正的函数fn            interval();  // 同时再次调用interval本身        }, time)    }    interval();  // 开始执行    // 返回用于关闭定时器的函数    return () => clearTimeout(timer);}
// 测试const cancel = mySetInterval(() => console.log(1), 400);setTimeout(() => { cancel();}, 1000); // 打印两次1
复制代码

闭包的应用场景

  • 柯里化 bind

  • 模块

渲染机制

1. 浏览器如何渲染网页


概述:浏览器渲染一共有五步


  1. 处理 HTML 并构建 DOM 树。

  2. 处理 CSS构建 CSSOM 树。

  3. DOMCSSOM 合并成一个渲染树。

  4. 根据渲染树来布局,计算每个节点的位置。

  5. 调用 GPU 绘制,合成图层,显示在屏幕上


第四步和第五步是最耗时的部分,这两步合起来,就是我们通常所说的渲染


具体如下图过程如下图所示




渲染


  • 网页生成的时候,至少会渲染一次

  • 在用户访问的过程中,还会不断重新渲染


重新渲染需要重复之前的第四步(重新生成布局)+第五步(重新绘制)或者只有第五个步(重新绘制)


  • 在构建 CSSOM 树时,会阻塞渲染,直至 CSSOM树构建完成。并且构建 CSSOM 树是一个十分消耗性能的过程,所以应该尽量保证层级扁平,减少过度层叠,越是具体的 CSS 选择器,执行速度越慢

  • HTML 解析到 script 标签时,会暂停构建 DOM,完成后才会从暂停的地方重新开始。也就是说,如果你想首屏渲染的越快,就越不应该在首屏就加载 JS 文件。并且CSS也会影响 JS 的执行,只有当解析完样式表才会执行 JS,所以也可以认为这种情况下,CSS 也会暂停构建 DOM


2. 浏览器渲染五个阶段


2.1 第一步:解析 HTML 标签,构建 DOM 树


在这个阶段,引擎开始解析html,解析出来的结果会成为一棵domdom的目的至少有2


  • 作为下个阶段渲染树状图的输入

  • 成为网页和脚本的交互界面。(最常用的就是getElementById等等)


当解析器到达 script 标签的时候,发生下面四件事情


  1. html解析器停止解析,

  2. 如果是外部脚本,就从外部网络获取脚本代码

  3. 将控制权交给js引擎,执行js代码

  4. 恢复html解析器的控制权


由此可以得到第一个结论 1


  • 由于<script>标签是阻塞解析的,将脚本放在网页尾部会加速代码渲染。

  • deferasync属性也能有助于加载外部脚本。

  • defer使得脚本会在dom完整构建之后执行;

  • async标签使得脚本只有在完全available才执行,并且是以非阻塞的方式进行的


2.2 第二步:解析 CSS 标签,构建 CSSOM 树


  • 我们已经看到html解析器碰到脚本后会做的事情,接下来我们看下html解析器碰到样式表会发生的情况

  • js会阻塞解析,因为它会修改文档(document)。css不会修改文档的结构,如果这样的话,似乎看起来css样式不会阻塞浏览器html解析。但是事实上 css样式表是阻塞的。阻塞是指当cssom树建立好之后才会进行下一步的解析渲染


通过以下手段可以减轻 cssom 带来的影响


  • script脚本放在页面底部

  • 尽可能快的加载css样式表

  • 将样式表按照media typemedia query区分,这样有助于我们将css资源标记成非阻塞渲染的资源。

  • 非阻塞的资源还是会被浏览器下载,只是优先级较低


2.3 第三步:把 DOM 和 CSSOM 组合成渲染树(render tree)



2.4 第四步:在渲染树的基础上进行布局,计算每个节点的几何结构


布局(layout):定位坐标和大小,是否换行,各种position, overflow, z-index属性


2.5 调用 GPU 绘制,合成图层,显示在屏幕上


将渲染树的各个节点绘制到屏幕上,这一步被称为绘制painting


3. 渲染优化相关


3.1 Load 和 DOMContentLoaded 区别


  • Load 事件触发代表页面中的 DOMCSSJS,图片已经全部加载完毕。

  • DOMContentLoaded 事件触发代表初始的 HTML 被完全加载和解析,不需要等待 CSSJS,图片加载


3.2 图层


一般来说,可以把普通文档流看成一个图层。特定的属性可以生成一个新的图层。不同的图层渲染互不影响,所以对于某些频繁需要渲染的建议单独生成一个新图层,提高性能。但也不能生成过多的图层,会引起反作用。


通过以下几个常用属性可以生成新图层


  • 3D 变换:translate3dtranslateZ

  • will-change

  • videoiframe 标签

  • 通过动画实现的 opacity 动画转换

  • position: fixed


3.3 重绘(Repaint)和回流(Reflow)


重绘和回流是渲染步骤中的一小节,但是这两个步骤对于性能影响很大


  • 重绘是当节点需要更改外观而不会影响布局的,比如改变 color 就叫称为重绘

  • 回流是布局或者几何属性需要改变就称为回流。


回流必定会发生重绘,重绘不一定会引发回流。回流所需的成本比重绘高的多,改变深层次的节点很可能导致父节点的一系列回流


以下几个动作可能会导致性能问题


  • 改变 window 大小

  • 改变字体

  • 添加或删除样式

  • 文字改变

  • 定位或者浮动

  • 盒模型


很多人不知道的是,重绘和回流其实和 Event loop 有关


  • Event loop 执行完Microtasks 后,会判断 document 是否需要更新。因为浏览器是 60Hz 的刷新率,每 16ms 才会更新一次。

  • 然后判断是否有 resize 或者 scroll ,有的话会去触发事件,所以 resizescroll 事件也是至少 16ms才会触发一次,并且自带节流功能。

  • 判断是否触发了 media query

  • 更新动画并且发送事件

  • 判断是否有全屏操作事件

  • 执行 requestAnimationFrame 回调

  • 执行 IntersectionObserver 回调,该方法用于判断元素是否可见,可以用于懒加载上,但是兼容性不好

  • 更新界面

  • 以上就是一帧中可能会做的事情。如果在一帧中有空闲时间,就会去执行 requestIdleCallback 回调


常见的引起重绘的属性


  • color

  • border-style

  • visibility

  • background

  • text-decoration

  • background-image

  • background-position

  • background-repeat

  • outline-color

  • outline

  • outline-style

  • border-radius

  • outline-width

  • box-shadow

  • background-size


3.4 常见引起回流属性和方法


任何会改变元素几何信息(元素的位置和尺寸大小)的操作,都会触发重排,下面列一些栗子


  • 添加或者删除可见的DOM元素;

  • 元素尺寸改变——边距、填充、边框、宽度和高度

  • 内容变化,比如用户在input框中输入文字

  • 浏览器窗口尺寸改变——resize事件发生时

  • 计算 offsetWidthoffsetHeight 属性

  • 设置 style 属性的值


回流影响的范围


由于浏览器渲染界面是基于流失布局模型的,所以触发重排时会对周围 DOM 重新排列,影响的范围有两种


  • 全局范围:从根节点html开始对整个渲染树进行重新布局。

  • 局部范围:对渲染树的某部分或某一个渲染对象进行重新布局


全局范围回流


<body>  <div class="hello">    <h4>hello</h4>    <p><strong>Name:</strong>BDing</p>    <h5>male</h5>    <ol>      <li>coding</li>      <li>loving</li>    </ol>  </div></body>
复制代码


p节点上发生reflow时,hellobody也会重新渲染,甚至h5ol都会收到影响


局部范围回流


用局部布局来解释这种现象:把一个dom的宽高之类的几何信息定死,然后在dom内部触发重排,就只会重新渲染该dom内部的元素,而不会影响到外界


3.5 减少重绘和回流


使用 translate 替代 top


<div class="test"></div><style>    .test {        position: absolute;        top: 10px;        width: 100px;        height: 100px;        background: red;    }</style><script>    setTimeout(() => {        // 引起回流        document.querySelector('.test').style.top = '100px'    }, 1000)</script>
复制代码


  • 使用 visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局)

  • DOM 离线后修改,比如:先把 DOMdisplay:none (有一次 Reflow),然后你修改100次,然后再把它显示出来

  • 不要把 DOM 结点的属性值放在一个循环里当成循环里的变量


for(let i = 0; i < 1000; i++) {    // 获取 offsetTop 会导致回流,因为需要去获取正确的值    console.log(document.querySelector('.test').style.offsetTop)}
复制代码


  • 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局

  • 动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使用 requestAnimationFrame

  • CSS选择符从右往左匹配查找,避免 DOM深度过深

  • 将频繁运行的动画变为图层,图层能够阻止该节点回流影响别的元素。比如对于 video标签,浏览器会自动将该节点变为图层。



事件机制

涉及面试题:事件的触发过程是怎么样的?知道什么是事件代理嘛?


1. 简介


事件流是一个事件沿着特定数据结构传播的过程。冒泡和捕获是事件流在DOM中两种不同的传播方法


事件流有三个阶段


  • 事件捕获阶段

  • 处于目标阶段

  • 事件冒泡阶段


事件捕获


事件捕获(event capturing):通俗的理解就是,当鼠标点击或者触发dom事件时,浏览器会从根节点开始由外到内进行事件传播,即点击了子元素,如果父元素通过事件捕获方式注册了对应的事件的话,会先触发父元素绑定的事件


事件冒泡


事件冒泡(dubbed bubbling):与事件捕获恰恰相反,事件冒泡顺序是由内到外进行事件传播,直到根节点


无论是事件捕获还是事件冒泡,它们都有一个共同的行为,就是事件传播



2. 捕获和冒泡


<div id="div1">  <div id="div2"></div></div>
<script> let div1 = document.getElementById('div1'); let div2 = document.getElementById('div2');
div1.onClick = function(){ alert('1') }
div2.onClick = function(){ alert('2'); }
</script>
复制代码


当点击 div2时,会弹出两个弹出框。在 ie8/9/10chrome浏览器,会先弹出”2”再弹出“1”,这就是事件冒泡:事件从最底层的节点向上冒泡传播。事件捕获则跟事件冒泡相反


W3C 的标准是先捕获再冒泡, addEventListener的第三个参数决定把事件注册在捕获(true)还是冒泡(false)


3. 事件对象



4. 事件流阻止


在一些情况下需要阻止事件流的传播,阻止默认动作的发生


  • event.preventDefault():取消事件对象的默认动作以及继续传播。

  • event.stopPropagation()/ event.cancelBubble = true:阻止事件冒泡。


事件的阻止在不同浏览器有不同处理


  • IE下使用 event.returnValue= false

  • 在非IE下则使用 event.preventDefault()进行阻止


preventDefault 与 stopPropagation 的区别


  • preventDefault告诉浏览器不用执行与事件相关联的默认动作(如表单提交)

  • stopPropagation是停止事件继续冒泡,但是对 IE9 以下的浏览器无效


5. 事件注册


  • 通常我们使用 addEventListener 注册事件,该函数的第三个参数可以是布尔值,也可以是对象。对于布尔值 useCapture 参数来说,该参数默认值为 falseuseCapture 决定了注册的事件是捕获事件还是冒泡事件

  • 一般来说,我们只希望事件只触发在目标上,这时候可以使用 stopPropagation 来阻止事件的进一步传播。通常我们认为 stopPropagation 是用来阻止事件冒泡的,其实该函数也可以阻止捕获事件。stopImmediatePropagation 同样也能实现阻止事件,但是还能阻止该事件目标执行别的注册事件


node.addEventListener('click',(event) =>{    event.stopImmediatePropagation()    console.log('冒泡')},false);// 点击 node 只会执行上面的函数,该函数不会执行node.addEventListener('click',(event) => {    console.log('捕获 ')},true)
复制代码


6. 事件委托


  • js中性能优化的其中一个主要思想是减少dom操作。

  • 节省内存

  • 不需要给子节点注销事件


假设有100li,每个li有相同的点击事件。如果为每个Li都添加事件,则会造成dom访问次数过多,引起浏览器重绘与重排的次数过多,性能则会降低。 使用事件委托则可以解决这样的问题


原理


实现事件委托是利用了事件的冒泡原理实现的。当我们为最外层的节点添加点击事件,那么里面的ullia的点击事件都会冒泡到最外层节点上,委托它代为执行事件


<ul id="ul">    <li>1</li>    <li>2</li>    <li>3</li></ul><script>  window.onload = function(){    var ulEle = document.getElementById('ul');    ul.onclick = function(ev){        //兼容IE        ev = ev || window.event;        var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){ alert( target.innerHTML); }
} }</script>
复制代码

UDP 协议为什么不可靠?

UDP 在传输数据之前不需要先建立连接,远地主机的运输层在接收到 UDP 报文后,不需要确认,提供不可靠交付。总结就以下四点:


  • 不保证消息交付:不确认,不重传,无超时

  • 不保证交付顺序:不设置包序号,不重排,不会发生队首阻塞

  • 不跟踪连接状态:不必建立连接或重启状态机

  • 不进行拥塞控制:不内置客户端或网络反馈机制

什么是 XSS 攻击?

(1)概念

XSS 攻击指的是跨站脚本攻击,是一种代码注入攻击。攻击者通过在网站注入恶意脚本,使之在用户的浏览器上运行,从而盗取用户的信息如 cookie 等。


XSS 的本质是因为网站没有对恶意代码进行过滤,与正常的代码混合在一起了,浏览器没有办法分辨哪些脚本是可信的,从而导致了恶意代码的执行。


攻击者可以通过这种攻击方式可以进行以下操作:


  • 获取页面的数据,如 DOM、cookie、localStorage;

  • DOS 攻击,发送合理请求,占用服务器资源,从而使用户无法访问服务器;

  • 破坏页面结构;

  • 流量劫持(将链接指向某网站);

(2)攻击类型

XSS 可以分为存储型、反射型和 DOM 型:


  • 存储型指的是恶意脚本会存储在目标服务器上,当浏览器请求数据时,脚本从服务器传回并执行。

  • 反射型指的是攻击者诱导用户访问一个带有恶意代码的 URL 后,服务器端接收数据后处理,然后把带有恶意代码的数据发送到浏览器端,浏览器端解析这段带有 XSS 代码的数据后当做脚本执行,最终完成 XSS 攻击。 

  • DOM 型指的通过修改页面的 DOM 节点形成的 XSS。


1)存储型 XSS 的攻击步骤:


  1. 攻击者将恶意代码提交到⽬标⽹站的数据库中。

  2. ⽤户打开⽬标⽹站时,⽹站服务端将恶意代码从数据库取出,拼接在 HTML 中返回给浏览器。

  3. ⽤户浏览器接收到响应后解析执⾏,混在其中的恶意代码也被执⾏。

  4. 恶意代码窃取⽤户数据并发送到攻击者的⽹站,或者冒充⽤户的⾏为,调⽤⽬标⽹站接⼝执⾏攻击者指定的操作。


这种攻击常⻅于带有⽤户保存数据的⽹站功能,如论坛发帖、商品评论、⽤户私信等。


2)反射型 XSS 的攻击步骤:


  1. 攻击者构造出特殊的 URL,其中包含恶意代码。

  2. ⽤户打开带有恶意代码的 URL 时,⽹站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器。

  3. ⽤户浏览器接收到响应后解析执⾏,混在其中的恶意代码也被执⾏。

  4. 恶意代码窃取⽤户数据并发送到攻击者的⽹站,或者冒充⽤户的⾏为,调⽤⽬标⽹站接⼝执⾏攻击者指定的操作。


反射型 XSS 跟存储型 XSS 的区别是:存储型 XSS 的恶意代码存在数据库⾥,反射型 XSS 的恶意代码存在 URL ⾥。


反射型 XSS 漏洞常⻅于通过 URL 传递参数的功能,如⽹站搜索、跳转等。 由于需要⽤户主动打开恶意的 URL 才能⽣效,攻击者往往会结合多种⼿段诱导⽤户点击。


3)DOM 型 XSS 的攻击步骤:


  1. 攻击者构造出特殊的 URL,其中包含恶意代码。

  2. ⽤户打开带有恶意代码的 URL。

  3. ⽤户浏览器接收到响应后解析执⾏,前端 JavaScript 取出 URL 中的恶意代码并执⾏。

  4. 恶意代码窃取⽤户数据并发送到攻击者的⽹站,或者冒充⽤户的⾏为,调⽤⽬标⽹站接⼝执⾏攻击者指定的操作。


DOM 型 XSS 跟前两种 XSS 的区别:DOM 型 XSS 攻击中,取出和执⾏恶意代码由浏览器端完成,属于前端 JavaScript ⾃身的安全漏洞,⽽其他两种 XSS 都属于服务端的安全漏洞。


用户头像

loveX001

关注

还未添加个人签名 2022-09-01 加入

还未添加个人简介

评论

发布
暂无评论
20道前端高频面试题(附答案)_JavaScript_loveX001_InfoQ写作社区