跨域

跨域本质是浏览器基于同源策略的一种安全手段

同源策略

浏览器的安全功能,协议、域名、端口一致则是同源,非同源的限制:

  • 无法通过 XMLHttpRequest 或 fetch 发起跨域请求
  • 无法访问不同源的文档的 DOM
  • 无法读取其他域的 Cookie、Storage

简单请求

  • 使用下列方法之一:GETPOSTHEAD
  • 标头字段自定义的只能有:AcceptAccept-LanguageContent-TypeContent-LanguageRange
  • Content-Type 所指定的媒体类型的值仅限于下列三者之一:text/plainmultipart/form-dataapplication/x-www-form-urlencoded

针对简单请求,浏览器不会拦截。但是非简单请求,浏览器会发送 预检请求(OPTIONS

解决跨域方法

1.CORS (Cross-Origin Resource Sharing,跨域资源共享)

服务端设置响应头:Access-Control-Allow-Origin,来允许或限制资源的跨域访问

2.代理服务器

在服务器端设置代理,将前端请求先发送到同源的后端服务器,然后由后端服务器转发请求到目标服务器

3.JSONP

通过创建 <script> 标签来请求跨域数据,然后服务器响应时将数据包装在回调函数中,实现跨域的原理是利用 script 标签没有跨域限制,通过 src 指向一个 URL,最后跟一个回调函数 callback(仅支持 GET 请求)

4.WebSocket

WebSocket 连接不受同源策略限制

跨域问题?同源策略大全 - 掘金

安全问题

1.XSS (Cross-site scripting) 跨站脚本攻击

是一种代码注入攻击。攻击者将恶意代码植入到提供给其它用户使用的页面中,盗取存储在客户端的 cookie 或者用于识别客户端身份的敏感信息
根据攻击的来源,XSS 攻击可分为:

  • 存储型:攻击者将恶意代码提交到目标网站的数据库中
  • 反射型:攻击者构造出特殊的 URL,网站服务端将恶意代码从 URL 中取出,拼接在 HTML 中返回给浏览器
  • DOM 型:攻击者构造出特殊的 URL,前端 JS 执行恶意代码

预防

  • 对用户输入和提交的内容进行转义和过滤
  • 在使用 .innerHTML、.outerHTML、document.write() 时要注意,不要把不可信的数据作为 HTML 插到页面上
  • httpOnly Cookie: 禁止 JavaScript 读取某些敏感 Cookie

2.CSRF (Cross-site request forgery) 跨站请求伪造

用户在已登录网站的情况下,攻击者通过引诱用户访问一个恶意网站或链接,发送伪造的请求到已登录的网站地址。由于浏览器会自动附带当前用户的身份验证信息(如 Cookies),目标应用程序会误以为该请求是用户自身发起的合法请求

预防

  • 请求信息中携带 token
  • 将 Cookie 的 SameSite 属性设置为 StrictLax,防止跨站请求携带 Cookies

3.点击劫持

攻击者将需要攻击的网站通过 iframe 嵌套的方式嵌入自己的网页中,并将 iframe 设置为透明,在页面中透出一个按钮诱导用户点击

预防

设置 HTTP 响应头 X-Frame-Options

  • DENY:禁止任何页面通过 iframe 嵌入当前页面
  • SAMEORIGIN:允许相同源的页面通过 iframe 嵌入当前页面

性能优化

资源方面:

  • 图片压缩
  • gzip 压缩

打包方面:

  • tree-shaking 去除无用代码
  • 使用 plugin 压缩代码
  • 代码进行拆分分离
  • 进行并发构建(HappyPack 插件)

代码方面:

  • 路由懒加载
  • 按需引入第三方包代码
  • HTML 中的 JS 文件使用 defer 或 async 加载
  • 大数据使用懒加载
  • 减少全局引入资源(如字体文件),页面访问时再加载
  • CSS 合理使用选择器,不要嵌套太深
  • 减少 DOM 操作
  • 使用预加载 prefetch 对将来可能用到的资源进行提前缓存

网络方面:

  • HTTP 缓存
  • 使用 CDN 存放资源

地址栏输入 URL 敲下回车后发生了什么

  1. 浏览器解析 URL
  2. DNS 解析(见 域名解析过程
  3. 建立 TCP 连接(见 TCP三次握手
  4. 发送 HTTP 请求
  5. 接收 HTTP 响应
  6. 页面渲染(见 浏览器渲染过程

事件循环

JavaScript 是单线程的语言,所有任务(同步/异步)都在主线程执行,事件循环是实现单线程非阻塞的机制

JavaScript 执行的异步代码分为宏任务和微任务

  • 宏任务(MacroTask):scriptsetTimeoutsetInterval、I/O 操作
  • 微任务(MicroTask):Promise.then/catch/finallyMutationObserver

requestAnimationFrame 发生的顺序会是在下次页面重绘之前操作

事件循环流程

  1. 所有任务都会在主线程上执行,形成一个执行栈,执行整个脚本的同步代码
  2. 遇到异步任务,放入任务队列
  3. 执行完执行栈的同步代码
  4. 执行所有微任务,直到微任务队列清空
  5. 再执行一个宏任务
  6. 重复步骤 4~5,直到所有任务完成

请说明浏览器中的事件循环 (Event Loop)|ExplainThis
最常见的事件循环 (Event Loop) 面试题目汇整|ExplainThis
JS: 一战吃透Promise精修版 - 掘金

Tip

  • await 执行完后面的代码之后,会将它下面的代码放入微任务队列
  • .then 后面再接 .then 会继续放入微任务队列末尾,一次执行完

IntersectionObserver

检测目标元素与视口(viewport)或某个祖先元素交集变化
应用:懒加载图片、无限滚动