面试题

DNS 解析流程

在浏览器输入一个 url 地址后,浏览器首先会查看其自身对 DNS 记录的缓存,如果有,直接用缓存中记录的 IP 访问服务器,如果没有,向本地域名服务器发起查询请求。
本地域名服务器接收到请求后,会先查看操作系统的 DNS 缓存,如果有,获取缓存中的记录返回给浏览器,如果没有,迭代地向根域名服务器、顶级域名服务器发起查询请求,直至返回最终的 IP。

本地域名服务器拿到 IP 后,将其写入操作系统的 DNS 缓存,并返回给浏览器。
浏览器拿到 IP 后,将其写入到自身的 DNS 缓存,并向服务器发起请求。


!DOCTYPE html 的作用

<!DOCTYPE html> 的作用就是告诉浏览器要以标准模式来解析 HTML 页面。
浏览器的兼容性模式(document.compatMode)包括:

  • BackCompat:怪异模式(默认),浏览器使用自己的模式解析渲染页面
  • CSS1Compat:标准模式,浏览器使用 W3C 的标准解析渲染页面

如果不设置 <!DOCTYPE html>,那么 document.compatMode 默认是 BackCompat,浏览器按照自己的方式解析渲染页面,那么,在不同的浏览器就会显示不同的样式。
如果你的页面添加了 <!DOCTYPE html>,那么就等同于开启了标准模式,这样浏览器就得老老实实的按照 W3C 的标准解析渲染页面,这样一来,你的页面在所有的浏览器里显示的就都是一个样子了。


var、let、const的区别

  1. var 定义的变量,没有块的概念,可以跨块访问,不能跨函数访问

  2. let 定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问

  3. const 用来定义常量,使用时必须初始化,只能在块作用域里访问,而且不能修改


为什么要 promise 或是异步

解决多层回调问题(回调地狱)。


什么是 axios

axios是基于promise用于浏览器和node.js的http客户端。

axios主要用于向后台发起请求,还有在请求中做更多的可控功能。


axios、ajax、fetch 三者的区别

  • ajax隶属于原始js,核心使用XMLHttpRequest对象,多个请求之间如果有先后关系的话,就会出现回调地狱。

  • Fetch是基于promise设计的,它不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象。

  • axios不是原生JS的,需要进行安装,它可以在客户端使用,也可以在nodejs端使用。Axios也可以在请求和响应阶段进行拦截。同样也是基于promise对象的。


CDN 原理

CDN 的基本原理是广泛采用各种缓存服务器,将这些缓存服务器分布到用户访问相对集中的地区或网络中,在用户访问网站时,利用全局负载技术将用户的访问指向距离最近的工作正常的缓存服务器上,由缓存服务器直接响应用户请求。


CDN 获取最近节点资源的算法是什么

DNS分地区解析


TCP 和 UDP

    TCP:面向连接,三次握手,四次挥手;稳定;面向字节流

    UDP:面向无连接;不稳定;面向报文


http 状态码

302:暂时重定向

304:表示页面未更新

400 Bad Request:表示请求报文中存在语法错误

403 Forbidden:服务器拒绝该次访问(访问权限出现问题)

404 Not Found:表示服务器上无法找到请求的资源,除此之外,也可以在服务器拒绝请求但不想给拒绝原因时使用

500 Inter Server Error:表示服务器在执行请求时发生了错误,也有可能是web应用存在的bug或某些临时的错误时

501:服务器不具有请求功能

502:网关错误

503 Server Unavailable:表示服务器暂时处于超负载或正在进行停机维护,无法处理请求

504:网关超时


js 依赖模块

Import require


画几何图形的技术有哪些

css,canvas,svg


http 头信息

  1. Accept:告诉WEB服务器自己接受什么介质类型

  2. Accept-Charset:浏览器申明自己接收的字符集

  3. Cache-Control:控制缓存

  4. Connection:请求:close(告诉WEB服务器或者代理服务器,在完成本次请求的响应后,断开连接,不要等待本次连接的后续请求了)


Web 缓存机制

  1. 浏览器第一次加载资源,服务器返回200,浏览器将资源文件从服务器上请求下载下来,并把 response header 及该请求的返回时间一并缓存;

  2. 下一次加载资源时,先比较当前时间和上一次返回 200 时的时间差,如果没有超过 cache-control 设置的 max-age,则没有过期,命中强缓存,不发请求直接从本地缓存读取该文件(如果浏览器不支持 HTTP1.1,则用 expires 判断是否过期);如果时间过期,则向服务器发送 header 带有 If-None-Match 和 If-Modified-Since 的请求

  3. 服务器收到请求后,优先根据 Etag 的值判断被请求的文件有没有做修改,Etag 值一致则没有修改,命中协商缓存,返回 304;如果不一致则有改动,直接返回新的资源文件带上新的 Etag 值并返回 200;

  4. 如果服务器收到的请求没有 Etag 值,则将 If-Modified-Since 和被请求文件的最后修改时间做比对,一致则命中协商缓存,返回 304;不一致则返回新的 last-modified 和文件并返回 200。


Get 和 post区别

(1)Get是从服务器上获得数据,而Post则是向服务器传递数据的。

(2)Get是不安全的,很可能你的一些操作会被第三方看到,而Post的所有操作多用户来说是不可见的。

(3)Get 传输的数据量小,主要是因为它受约于 URL 长度的限制,而 Post 可以传输大量的数据,所以我们在传文件的时候会用 Post。

(4)Get限制 From 表单的数据集的值必须为 ASCLL 字符,而 Post 支持整个 ISO10646 字符集。


跨域请求

概念:如果 “协议 + 域名 + 端口号” 均相同,就是同域,否则是跨域。

解决方法:

(1)CORS请求:它允许浏览器向声明了 CORS 的跨域服务器,发出 XMLHttpRequest 请求。

(2)JSONP请求:动态添加 script 标签来调用服务器提供的 js 脚本。

 JSONP请求,缺点是仅支持 GET 请求,CORS 比 JSONP 更强大,支持所有类型的 HTTP 请求。

(3)postMessage:如果两个网页不同源,就无法拿到对方的DOM。典型的例子是 iframe 窗口和 window.open 方法打开的窗口,它们与父窗口无法通信。window.postMessage 方法允许跨窗口通信,不论这两个窗口是否同源。postMessage 方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即”协议 + 域名 + 端口”。也可以设为*,表示不限制域名,向所有窗口发送。

(4)  WebSocket:Websocket 是 HTML5 的一个持久化的协议,它实现了浏览器与服务器的全双工通信,同时也是跨域的一种解决方案。

(5) 修改 document.domain 跨子域:两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致,否则无法利用 document.domain 进行跨域。例如把 domain 属性的值设置为 “xxx.com” ,那么 ”aaa.xxx.com” 和 ”bbb.xxx.com” 就可以进行通信了。


事件模型和事件代理(事件委托)

事件模型:是指一个事件发生后,会在子元素和父元素之间传播。

事件代理:事件委托是利用事件的冒泡原理来实现的,何为事件冒泡呢?就是事件从最深的节点开始,然后逐步向上传播事件。


事件委托

事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。

举个例子:页面上有这么一个节点树,div>ul>li>a,比如给最里面的 a 加一个 click 点击事件,那么这个事件就会一层一层的往外执行,执行顺序 a>li>ul>div,有这样一个机制,那么我们给最外面的 div 加点击事件,那么里面的 ul,li,a 做点击事件的时候,都会冒泡到最外层的 div 上,所以都会触发,这就是事件委托,委托它们父级代为执行事件。

可以减少 Dom 的操作次数,减少内存,从而提高性能。

适合用事件委托的事件:click,mousedown,mouseup,keydown,keyup,keypress。

不适合的就有很多了,举个例子,mousemove,每次都要计算它的位置,非常不好把控,在不如说 focus,blur 之类的,本身就没用冒泡的特性,自然就不能用事件委托了。

事件冒泡:从被触发事件逐层向上触发父级事件。

事件捕获:从被触发事件逐层向下触发子级事件。

事件冒泡和事件捕获可以通过 addEventListener(触发事件的动作,回调函数,布尔值) 函数实现:第三个参数为默认值 false 是事件冒泡;为 true 是事件捕获。


使元素消失的方法有哪些

1、opacity:0,该元素隐藏起来了,但不会改变页面布局,并且,如果该元素已经绑定一些事件,如click事件,那么点击该区域,也能触发点击事件的

2、visibility:hidden,该元素隐藏起来了,但不会改变页面布局,但是不会触发该元素已经绑定的事件

3、 display:none,把元素隐藏起来,并且会改变页面布局,可以理解成在页面中把该元素删除掉


call  apply  bind 区别

call,apply,bind 这三个方法其实都是继承自 Function.prototype 的。

(1)函数实例的 call 方法,可以指定该函数内部 this 的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。并且会立即执行该函数。

call() 方法可以传递两个参数。第一个参数是指定函数内部中 this 的指向(也就是函数执行时所在的作用域),第二个参数是函数调用时需要传递的参数。

第一个参数是必须的,可以是 null,undefined,this,但是不能为空。设置为 null,undefined,this 表明函数 keith 此时处于全局作用域。

(2)apply 方法的作用与 call 方法类似,也是改变 this 指向(函数执行时所在的作用域),然后在指定的作用域中,调用该函数。同时也会立即执行该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
function keith(a, b) {

console.log(a + b);

}

keith.apply(null, [2, 3]); //5

// 应用: 求数组中的最大值:

var a = [2, 4, 5, 7, 8, 10];

console.log(Math.max.apply(null, a));

 

(3)bind 方法用于指定函数内部的 this 指向(执行时所在的作用域),然后返回一个新函数。bind 方法并非立即执行一个函数。

总结:

a:第一个参数都是指定函数内部中 this 的指向(函数执行时所在的作用域),然后根据指定的作用域,调用该函数。

b:都可以在函数调用时传递参数。call,bind 方法需要直接传入,而 apply 方法需要以数组的形式传入。

c:call,apply 方法是在调用之后立即执行函数,而 bind 方法没有立即执行,需要将函数再执行一遍。有点闭包的味道。


MVVM

响应式,双向数据绑定,即MVVM。是指数据层(Model)-视图层(View)-数据视图(ViewModel)的响应式框架。它包括:

1.修改 View 层,Model对应数据发生变化。

2.Model 数据变化,不需要查找 DOM,直接更新 View


v-if 和 v-show 的区别

v-if 的原理是根据判断条件来动态的进行增删 DOM 元素,条件为真进行渲染,为假不渲染。

v-show 是根据判断条件来动态的进行显示和隐藏元素,它总是渲染 DOM 元素。

频繁的进行增删 DOM 操作会影响页面加载速度和性能。


多页应用与单页应用

(1)多页应用

概念:每一次页面跳转的时候,后台服务器都会给返回一个新的 html 文档,这种类型的网站也就是多页网站,也叫做多页应用。

特点:首屏时间快、SEO 效果好、页面切换慢

A. 首屏时间叫做页面首个屏幕的内容展现的时间,当我们访问页面的时候,服务器返回一个html,页面就会展示出来,这个过程只经历了一个 HTTP 请求,所以页面展示的速度非常快。

B. 搜索引擎在做网页排名的时候,要根据网页内容才能给网页权重,来进行网页的排名。搜索引擎是可以识别 html 内容的,而我们每个页面所有的内容都放在 Html 中,所以这种多页应用,seo 排名效果好。

C. 因为每次跳转都需要发出一个 http 请求,如果网络比较慢,在页面之间来回跳转时,就会发现明显的卡顿。

(2)单页应用

概念:第一次进入页面的时候会请求一个 html 文件,刷新清除一下,切换到其他组件,此时路径也相应变化,但是并没有新的 html 文件请求,页面内容也变化了。

特点:页面切换快、首屏时间稍慢、SEO 差

A. 页面每次切换跳转时,并不需要做 html 文件的请求,这样就节约了很多 http 发送时延,我们在切换页面的时候速度很快。

B. 单页应用的首屏时间慢,首屏时需要请求一次 html,同时还要发送一次 js 请求,两次请求回来了,首屏才会展示出来。相对于多页应用,首屏时间慢。

C. SEO 效果差,因为搜索引擎只认识 html 里的内容,不认识js的内容,而单页应用的内容都是靠 js 渲染生成出来的,搜索引擎不识别这部分内容,也就不会给一个好的排名,会导致单页应用做出来的网页在百度和谷歌上的排名差。


可通过服务器端渲染技术(SSR)解决单页应用的缺点。

Vue 属于单页应用


首屏时间慢的优化方案

(1)使用CDN 资源,减小服务器压力

(2)路由懒加载:import 、require.ensure

(3)图片懒加载:为了减少服务器压力,优先加载可视区域的内容,其他部分等进入了可视域再加载,从而提高性能。

(4)按需加载第三方资源(组件库)


localStorage,Cookie 和 sessionStorage 区别

localStorage和sessionStorage一样都是用来存储客户端临时信息的对象。

(1)localStorage 生命周期是永久,这意味着除非用户显示在浏览器提供的 UI 上清除 localStorage 信息,否则这些信息将永远存在;sessionStorage 生命周期为当前窗口或标签页,一旦窗口或标签页被永久关闭了,那么所有通过 sessionStorage 存储的数据也就被清空了。

(2)浏览器的不同页面间可以共享相同的 localStorage(页面属于相同域名和端口),但是不同页面或标签页间无法共享 sessionStorage 的信息。

(3)cookie 的数据被请求头携带在浏览器和服务器之间传递,localStorage 的数据只保存在本地;cookie 保存数据大小不超过 4K,而 localStorage 要大得多,可以达到 5M 甚至更大;cookie 数据的过期时间由 expires 属性决定,即使浏览器关闭数据也不会消失。


input 中如何监听值的变化

onchange:当内容发生变化且失去焦点时触发。

oninput:内容发生变化时立即触发,但通过js改变值时不触发。

onpropertychange:内容发生变化时立即触发,包括通过js改变值时,IE专用。


节流与防抖

当频繁的触发一个事件时,会很影响性能并容易导致页面卡顿,所以要合并多次请求,通过函数做一个精确操作。这时就会用到函数防抖或者函数节流。

函数节流是:在固定的时间内触发事件,每隔 n 秒触发一次

函数防抖是:当你频繁触发后,n 秒内只执行一次


AMD  CMD  CommonJS

他们都是用于在模块化定义中使用的,AMD、CMD、CommonJs是ES5中提供的模块化编程的方案,import/export是ES6中定义新增的

(1)AMD:RequireJS 是 AMD 的一个实践,采用前置依赖,异步加载。

(2)CMD:SeaJS 是 CMD 的一个实践,采用就近依赖,同步加载。

(3)CommonJS:Nodejs 是 CommonJS 的一个实践,通过 module.exports 导出,通过 require 导入。同步加载。


盒子模型

content(width、height)、padding、border、margin

实际宽度 = width+2padding+2border+2*margin

实际高度 = height+2padding+2border+2*margin


animation

animation-name 指定要绑定到选择器的关键帧的名称
animation-duration 动画指定需要多少秒或毫秒完成
animation-timing-function 设置动画将如何完成一个周期
animation-delay 设置动画在启动前的延迟间隔。
animation-iteration-count 定义动画的播放次数。
animation-direction 指定是否应该轮流反向播放动画。
animation-fill-mode 规定当动画不播放时(当动画完成时,或当动画有一个延迟未开始播放时),要应用到元素的样式。
animation-play-state 指定动画是否正在运行或已暂停。

前端常见的攻击方式

(1)XSS(跨站脚本攻击)

特点:攻击者会往 web 页面嵌入 js 脚本

解决:在 http 请求头中为 cookie 添加 HttpOnly 属性

(2)CSRF(跨站点请求伪造)

特点:攻击者盗用了你的身份,以你的名义发送恶意请求

解决:验证 HTTP Referer 字段(记录了http请求的来源地址);在请求地址中添加 token 并验证;在 HTTP 头中自定义属性并验证。

(3)Http Heads

特点:http 协议在 head 和 body 之间有一个空行,攻击者会将 js 代码注入到其中

解决:过滤 header 中出现的非法字符


SSR(服务器端渲染)

概念:简单理解是将组件或页面通过服务器生成 html 字符串,再发送到浏览器。

如果一个页面没使用服务渲染,当请求页面时,返回的 body 里为空,之后执行 js 将 html 结构注入到 body 里,结合 css 显示出来;

如果一个页面使用了服务端渲染,当请求页面时,返回的 body 里已经有了首屏的 html 结构,之后结合 css 显示出来。

作用:更利于 SEO;缩短首屏时间。


判断活动页面

概念:活动页面是指当前正在使用、操作的浏览器页面(不包括最小化)。

判断方法:

使用 document.hidden 来判定是否隐藏:返回值为真,则页面隐藏;返回值为假,则页面为活动页。


XHR

XHR 是 XMLHttpRequest 的对象的简称。

(1)创建对象:

var xhr = new XMLHttpRequest();

(2)发送请求:

xhr.open(‘get’, ‘url’,  true);  // 第三个参数指定是否为异步

send() 方法接收一个参数,即要作为请求主体发送的数据。调用 send() 方法后,请求被分派到服务器。如果是 GET 方法,send() 方法无参数,或参数为 null;如果是 POST 方法,send() 方法的参数为要发送的数据。

(3)接收响应

如果需要接收的是异步响应,这就需要检测 XHR 对象的 readyState 属性,该属性表示请求响应过程的当前活动阶段。这个属性可取的值如下:

0(UNSENT):未初始化。尚未调用open()方法

1(OPENED):启动。已经调用open()方法,但尚未调用send()方法

2(HEADERS_RECEIVED):发送。己经调用send()方法,且接收到头信息

3(LOADING):接收。已经接收到部分响应主体信息

4(DONE):完成。已经接收到全部响应数据,而且已经可以在客户端使用了


正向代理与反向代理

1、正向代理其实是客户端的代理,帮助客户端访问其无法访问的服务器资源。反向代理则是服务器的代理,帮助服务器做负载均衡,安全防护等。

2、正向代理一般是客户端架设的,比如在自己的机器上安装一个代理软件。而反向代理一般是服务器架设的,比如在自己的机器集群中部署一个反向代理服务器。

3、正向代理中,服务器不知道真正的客户端到底是谁,以为访问自己的就是真实的客户端。而在反向代理中,客户端不知道真正的服务器是谁,以为自己访问的就是真实的服务器。

4、正向代理和反向代理的作用和目的不同。正向代理主要是用来解决访问限制问题。而反向代理则是提供负载均衡、安全防护等作用。二者均能提高访问速度。


CSS 选择器的优先级

  1. 在属性后面使用 !important 会覆盖页面内任何位置定义的元素样式。
  2. 作为style属性写在元素内的样式
  3. id选择器
  4. 类选择器
  5. 标签选择器
  6. 通配符选择器
  7. 继承
  8. 浏览器默认属性

同一级别中后写的会覆盖先写的样式。


伪元素,伪类

css 引入伪类和伪元素概念是为了格式化文档树以外的信息。也就是说,伪类和伪元素是用来修饰不在文档树中的部分。

伪类用于当已有元素处于的某个状态时,为其添加对应的样式,这个状态是根据用户行为而动态变化的。比如说,当用户悬停在指定的元素时,我们可以通过 :hover 来描述这个元素的状态。虽然它和普通的css类相似,可以为已有的元素添加样式,但是它只有处于 dom 树无法描述的状态下才能为元素添加样式,所以将其称为伪类。

伪元素用于创建一些不在文档树中的元素,并为其添加样式。比如说,我们可以通过 :before 来在一个元素前增加一些文本,并为这些文本添加样式。虽然用户可以看到这些文本,但是这些文本实际上不在文档树中。

伪类的操作对象是文档树中已有的元素,而伪元素则创建了一个文档数外的元素。因此,伪类与伪元素的区别在于:有没有创建一个文档树之外的元素。


JS数据类型

(1)一共有 8 种:Number、String、Boolean、Null、undefined、object、symbol、bigInt

(2) 基本类型(单类型): String、Number、boolean、null、undefined。

引用类型:object。里面包含的 function、Array、date

(3)typeof() 输出值:

x typeof(x)
‘good’ String
1, 2, 21.3 Number
true, false Boolean
undefined undefined
null Object 不存在的对象
NaN Number Number中的特殊数值
object function
[], {} object

(4)null 和 undefined 的区别:

undefined 是没有定义的,null 是定义了但是为空。


em 和 rem 的区别

em:em是一种相对长度单位,相对于自身元素的字号大小,如果没有设置即参照父容器的字号大小或浏览器默认字号大小。

rem: rem是css3的新标准也是一种相对长度单位,其相对于HTML根标签的字号大小。


JS 实现深拷贝的方法

(1)使用递归的方式

(2)通过 JSON 对象

1
2
3
4
5
6
7
function deepClone2(obj) {

let _obj = JSON.stringify(obj),

return JSON.parse(_obj);

}

注意:Object.assign()、Array.slice()、Arrary.concant() 都不是真正意义上的深拷贝,它们只能实现第一层的深拷贝,而之后的是浅拷贝。如 [1, 2, 3, [4, 5, 6], 7]。


margin 塌陷

在文档流中,父元素的高度默认是被子元素撑开的,也就是说子元素有多高父元素就有多高。但是当子元素设置浮动之后,子元素会完全脱离文档流,此时将会导致子元素无法撑开父元素的高度,导致父元素高度塌陷。

解决方法:

(1)根据BFC的启动条件,在父级元素上加一个overflow:hidden就可以,其他如上条件之一,如果情况合适均可。

(2)给父级元素添加一个边框,就可以解决;如果不希望看到边框,可以将边框的颜色设成背景色即可。


v-for 中 key 的作用

(1)提高渲染性能。当在进行列表渲染的时候,vue会直接对已有的标签进行复用,不会整个的将所有的标签全部重新删除和创建,只会重新渲染数据。

(2)避免数据混乱的情况出现 (如果元素中包含了有临时数据的元素,如果不用key就会产生数据混乱)


ajax 优缺点

优点:

1、提高了性能和速度

减少客户端和服务器之间的流量传输,同时减少了双方响应的时间,响应更快,因此提高了性能和速度。

2、交互性能好

使用ajax,可以开发更快,更具交互性的Web应用程序。

3、异步调用

AJAX对Web服务器进行异步调用。这意味着客户端浏览器在开始渲染之前避免等待所有数据到达。

4、节省带宽

基于Ajax的应用程序使用较少的服务器带宽,因为无需重新加载完整的页面。

缺点:

1、增加了设计和开发时间

2、比构建经典Web应用程序更复杂

3、AJAX应用程序中的安全性较低,因为所有文件都是在客户端下载的。

4、可能出现网络延迟问题

5、禁用JavaScript的浏览器无法使用该应用程序。


单点登录

单点登录(Single Sign On),简称 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
比如在企业内部多个应用系统(如考勤系统、财务系统、人事系统等)场景下,用户只需要登录一次,就可以访问多个应用系统。
简单来说就是,一次登录,全部登录!一次注销,全部注销!!
单点登录主要强调的是登录以后,各个系统间用户身份认证信息共享问题。
实现单点登录有以下集中方式:

使用场景:
各个系统的二级域名相同,比如都是以“.xxx.com”结尾,可以设置 cookie 的 domain 属性来实现共享 cookie。
用户在某一个系统登录成功后,服务器返回一个 cookie,用户再访问其它系统时,系统会获取此 cookie 进行验证,验证通过后则无需再次登录。

2. 使用 token

使用场景:
B 系统是通过在 A 系统中跳转访问的。
用户登录 A 系统成功后,服务器返回一个 token,当用户点击链接跳转到 B 系统时,将此 token 拼接到 url 后面,那么 B 系统就可以获取到此 token,然后将其携带到服务端进行验证,验证通过后则无需再次登录。

3. 使用 iframe

使用场景:
各个系统的二级域名并不完全相同,且不一定要通过在一个系统内跳转到另一个系统的方式来访问。
可以在 B 系统的登录页通过 iframe 内嵌 A 系统的登录页,即填写的账号密码以及登录操作都发生在 A 系统上。A 系统登录成功后,B 系统可以通过 postMessage 拿到 A 系统的 token。
如果直接在 A 系统登录,再登录 B 系统时,B 系统同样可以通过 postMessage 拿到 A 系统的 token。