概述
大家好,我是前端岚枫,今天主要跟大家分享我整理的笔记2021前端面试题系列:fetch与axios、浏览器内标签页之间的通讯方法、XSS 和CSRF以及如何防范,此方面内容在我们的工作中常用到, 也是面试官经常提问的问题,希望下面文章对大家有所帮助。
fetch与axios
问题分析
fetch与axios的定位认识。fetch是浏览器提供的api,axios是社区封装的一个组件。
fetch 是一个低层次的API,你可以把它考虑成原生的XHR,所以使用起来并不是那么舒服,需要进行封装。多年来,XMLHttpRequest
一直是web开发者的亲密助手。无论是直接的,还是间接的, 当我们谈及Ajax技术的时候,通常意思就是基于XMLHttpRequest
的Ajax,它是一种能够有效改进页面通信的技术。 Ajax的兴起是由于Google的Gmail所带动的,随后被广泛的应用到众多的Web产品(应用)中,可以认为, 开发者已经默认将XMLHttpRequest
作为了当前Web应用与远程资源进行通信的基础。 而本文将要介绍的内容则是XMLHttpRequest
的最新替代技术——Fetch API, 它是W3C的正式标准,下面将会介绍Fetch API的相关知识,以及探讨它所能使用的场景和能解决的问题。
一、fetch优势:
- 语法简洁,更加语义化
- 基于标准 Promise 实现,支持 async/await
- 更加底层,提供的API丰富(request, response)
- 脱离了XHR,是ES规范里新的实现方式
二、fetch存在问题
fetch是一个低层次的API,你可以把它考虑成原生的XHR,所以使用起来并不是那么舒服,需要进行封装。
- fetch只对网络请求报错,对400,500都当做成功的请求,服务器返回 400,500 错误码时并不会 reject,只有网络错误这些导致请求不能完成时,fetch 才会被 reject。
- fetch默认不会带cookie,需要添加配置项: fetch(url, {credentials: ‘include’})
- fetch不支持abort,不支持超时控制,使用setTimeout及Promise.reject的实现的超时控制并不能阻止请求过程继续在后台运行,造成了流量的浪费
- fetch没有办法原生监测请求的进度,而XHR可以
fetch('http://example.com/movies.json') //第二个参数 指定 post get
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,它本身具有以下特征:
- 从浏览器中创建 XMLHttpRequest
- 支持 Promise API
- 客户端支持防止CSRF
- 提供了一些并发请求的接口(重要,方便了很多的操作)
- 从 node.js 创建 http 请求
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换JSON数据
// axios举例
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
总结:axios既提供了并发的封装,也没有fetch的各种问题,而且体积也较小,当之无愧现在最应该选用的请求的方式。
面试题点
- fetch是规范底层api 浏览器原生支持的
- axios是封装好的框架
- fetch和axios的优缺点
回答思路
首先明确fetch和axios分别是个啥?然后阐述fetch和axios的优缺点
相关扩展
- axios的github仓库地址
- axios的api文档说明
- fetch的api规范MDN社区说明
- w3c和whatwg
浏览器内多个标签页之间的通讯
问题分析
本题主要考察多页应用中各个页签之间数据交互的技术手段。实现多页通讯主要有利用浏览器数据存储方式和服务器方式。浏览器数据存储的方式主要用本地存储方式解决。即调用 localStorage、Cookie等本地存储方式。服务器方式主要使用websocket技术使多页签都监听服务器推送事件来获得其他页签发送的数据。
浏览器存储:
1. 调用localStorage
在一个标签页里面使用 localStorage.setItem(key,value)添加(修改、删除)内容;
在另一个标签页里面监听 storage 事件。 即可得到 localstorge 存储的值,实现不同标签页之间的通信。
在一个标签页调用localStorage.setItem(name,val)
保存数据localStorage.removeItem(name)
删除数据的时候会触发 'storage’事件。
在另外一个标签页监听document对象的storage事件,在事件event对象属性中获取信息
event事件对象包含以下信息
- domain
- newValue
- oldValue
- key
标签页1:
<input id="name">
<input type="button" id="btn" value="提交">
<script type="text/javascript">
window.onload = function () {
var btnEle = document.getElementById('btn');
var nameEle = document.getElementById('name');
btnEle.onclick = function () {
var name = nameEle.value;
localStorage.setItem("name", name);
}
}
</script>
标签页2:
<script type="text/javascript">
window.onload = function () {
window.addEventListener("storage", function (event) {
console.log(event.key + "=" + event.newValue);
});
}
</script>
2. 调用 cookie+setInterval()
将要传递的信息存储在cookie中,每隔一定时间读取cookie信息,即可随时获取要传递的信息。
在A页面将需要传递的消息存储在cookie当中
在B页面设置setInterval,以一定的时间间隔去读取cookie的值。
页面1:
<input id="name">
<input type="button" id="btn" value="提交">
<script type="text/javascript">
$(function(){
$("#btn").click(function(){
var name=$("#name").val();
document.cookie="name="+name;
});
});
</script>
页面2:
<script type="text/javascript">
$(function(){
function getCookie(key) {
return JSON.parse("{"" + document.cookie.replace(/;s+/gim,"","").replace(/=/gim, "":"") + ""}")[key];
}
setInterval(function(){
console.log("name=" + getCookie("name"));
}, 10000);
});
</script>
3. 监听服务器事件
- ** websocket通讯**
WebSocket是全双工(full-duplex)通信自然可以实现多个标签页之间的通信。WebSocket是HTML5新增的协议,它的目的是在浏览器和服务器之间建立一个不受限的双向通信的通道,比如说,服务器可以在任意时刻发送消息给浏览器。为什么传统的HTTP协议不能做到WebSocket实现的功能?这是因为HTTP协议是一个请求-响应协议,请求必须先由浏览器发给服务器,服务器才能响应这个请求,再把数据发送给浏览器。也有人说,HTTP协议其实也能实现啊,比如用轮询或者Comet。这个机制的缺点一是实时性不够,二是频繁的请求会给服务器带来极大的压力。Comet本质上也是轮询,但是在没有消息的情况下,服务器先拖一段时间,等到有消息了再回复。这个机制暂时地解决了实时性问题,但是它带来了新的问题:以多线程模式运行的服务器会让大部分线程大部分时间都处于挂起状态,极大地浪费服务器资源。另外,一个HTTP连接在长时间没有数据传输的情况下,链路上的任何一个网关都可能关闭这个连接,而网关是我们不可控的,这就要求Comet连接必须定期发一些ping数据表示连接“正常工作”。WebSocket并不是全新的协议,而是利用了HTTP协议来建立连接。为什么WebSocket连接可以实现全双工通信而HTTP连接不行呢?实际上HTTP协议是建立在TCP协议之上的,TCP协议本身就实现了全双工通信,但是HTTP协议的请求-应答机制限制了全双工通信。WebSocket连接建立以后,其实只是简单规定了一下:接下来,咱们通信就不使用HTTP协议了,直接互相发数据吧。安全的WebSocket连接机制和HTTPS类似。首先,浏览器用wss://xxx创建WebSocket连接时,会先通过HTTPS创建安全的连接,然后,该HTTPS连接升级为WebSocket连接,底层通信走的仍然是安全的SSL/TLS协议。
WebSocket连接必须由浏览器发起,特点:
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。
(5)没有同源限制,客户端可以与任意服务器通信。
(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。
示例: 浏览器端代码
// Create WebSocket connection.
const socket = new WebSocket('ws://localhost:8080');
// Connection opened
socket.addEventListener('open', function (event) {
socket.send('Hello Server!');
});
// Listen for messages
socket.addEventListener('message', function (event) {
console.log('Message from server ', event.data);
});
** 2. html5浏览器的新特性SharedWorker**
普通的webworker直接使用new Worker()即可创建,这种webworker是当前页面专有的。然后还有种共享worker(SharedWorker),这种是可以多个标签页、iframe共同使用的。SharedWorker可以被多个window共同使用,但必须保证这些标签页都是同源的(相同的协议,主机和端口号)
首先新建一个js文件worker.js,具体代码如下:
// sharedWorker所要用到的js文件,不必打包到项目中,直接放到服务器即可
let data = '';
let onconnect = function (e) {
let port = e.ports[0];
port.onmessage = function (e) {
if (e.data === 'get') {
port.postMessage(data)
} else {
data = e.data
}
}
}
webworker端(暂且这样称呼)的代码就如上,只需注册一个onmessage监听信息的事件,客户端(即使用sharedWorker的标签页)发送message时就会触发。
注意webworker无法在本地使用,出于浏览器本身的安全机制,所以我这次的示例也是放在服务器上的,worker.js和index.html在同一目录。
因为客户端和webworker端的通信不像websocket那样是全双工的,所以客户端发送数据和接收数据要分成两步来处理。示例中会有两个按钮,分别对应的向sharedWorker发送数据的请求以及获取数据的请求,但他们本质上都是相同的事件–发送消息。
webworker端会进行判断,传递的数据为’get’时,就把变量data的值回传给客户端,其他情况,则把客户端传递过来的数据存储到data变量中。下面是客户端的代码:
// 这段代码是必须的,打开页面后注册SharedWorker,显示指定worker.port.start()方法建立与worker间的连接
if (typeof Worker === "undefined") {
alert('当前浏览器不支持webworker')
} else {
let worker = new SharedWorker('worker.js')
worker.port.addEventListener('message', (e) => {
console.log('来自worker的数据:', e.data);
}, false);
worker.port.start();
window.worker = worker;
}
// 获取和发送消息都是调用postMessage方法,我这里约定的是传递'get'表示获取数据。
window.worker.port.postMessage('get')
window.worker.port.postMessage('发送信息给worker')
页面A发送数据给worker,然后打开页面B,调用window.worker.port.postMessage('get'),即可收到页面A发送给worker的数据。
面试题点
什么是多页应用
两种浏览器存储方式实现多页签通讯
websocket 和 shareworker 实现多页通讯(了解)
回答思路
首先明确一下多页应用的应用场景,然后分别介绍浏览器存储方式和借助服务器方式实现多页通讯的实现关键技术。
相关扩展
- H5的多线程(Worker SharedWorker)使用详解
- SharedWorker api
- websocket
XSS、CSRF 以及如何防范
问题分析
在 Web 安全领域中,XSS 和 CSRF 是最常见的攻击方式。下面我们首先简单了解一下什么是 XSS 和 CSRF 。
XSS
,即 Cross Site Script,中译是跨站脚本攻击;
其原本缩写是 CSS,但为了和层叠样式表(Cascading Style Sheet)有所区分,因而在安全领域叫做 XSS。
XSS 攻击是指攻击者在网站上注入恶意的客户端代码,通过恶意脚本对客户端网页进行篡改,从而在用户浏览网页时,对用户浏览器进行控制或者获取用户隐私数据的一种攻击方式。
攻击者对客户端网页注入的恶意脚本一般包括 JavaScript,有时也会包含 HTML 和 Flash。有很多种方式进行 XSS 攻击,但它们的共同点为:将一些隐私数据像 cookie、session 发送给攻击者,将受害者重定向到一个由攻击者控制的网站,在受害者的机器上进行一些恶意操作。
XSS攻击可以分为3类:反射型(非持久型)、存储型(持久型)、基于DOM。
xss类型
1、反射型 (Reflected XSS ) 发出请求时,XSS代码出现在url中,作为输入提交到服务器端,服务器端解析后响应,XSS代码随响应内容一起传回给浏览器,最后浏览器解析执行XSS代码。这个过程像一次反射,所以叫反射型XSS。
2、存储型存 Stored XSS和 Reflected XSS的差别就在于,具有攻击性的脚本被保存到了服务器端(数据库,内存,文件系统)并且可以被普通用户完整的从服务的取得并执行,从而获得了在网络上传播的能力。
3、DOM型 (DOM-based or local XSS) 即基于DOM或本地的 XSS 攻击:其实是一种特殊类型的反射型 XSS,它是基于 DOM文档对象模型的一种漏洞。可以通过 DOM来动态修改页面内容,从客户端获取 DOM中的数据并在本地执行。基于这个特性,就可以利用 JS脚本来实现 XSS漏洞的利用。
实际情况下的攻击例子:
- 举例有这样一个网站,可以让你对某个文章输入评论:
防御措施:
(1)输入过滤,避免 XSS 的方法之一主要是将用户输入的内容进行过滤。对所有用户提交内容进行可靠的输入验证,包括对 URL、查询关键字、POST数据等,仅接受指定长度范围内、采用适当格式、采用所预期的字符的内容提交,对其他的一律过滤。(客户端和服务器都要)
(2)输出转义
例如: 往 HTML 标签之间插入不可信数据的时候,首先要做的就是对不可信数据进行 HTML Entity 编码 [HTML 字符实体](http://www.w3school.com.cn/html/html_entities.asp)
function htmlEncodeByRegExp (str){
var s = "";
if(str.length == 0) return "";
s = str.replace(/&/g,"&");
s = s.replace(/</g,"<");
s = s.replace(/>/g,">");
s = s.replace(/ /g," ");
s = s.replace(/'/g,"'");
s = s.replace(/"/g,""");
return s;
}
var tmpStr="<p>123</p>";
var html=htmlEncodeByRegExp (tmpStr)
console.log(html) //<p>123</p>
document.querySelector(".content").innerHTML=html; //<p>123</p>
(3)使用 HttpOnly Cookie
将重要的cookie标记为httponly,这样的话当浏览器向Web服务器发起请求的时就会带上cookie字段,但是在js脚本中却不能访问这个cookie,这样就避免了XSS攻击利用JavaScript的document.cookie获取cookie。
现代web开发框架如vue.js、react.js等,在设计的时候就考虑了XSS攻击对html插值进行了更进一步的抽象、过滤和转义,我们只要熟练正确地使用他们,就可以在大部分情况下避免XSS攻击。
CSRF
, 即Cross-site request forgery)中译是跨站请求伪造;CSRF 顾名思义,是伪造请求,冒充用户在站内的正常操作。我们知道,绝大多数网站是通过 cookie 等方式辨识用户身份(包括使用服务器端 Session 的网站,因为 Session ID 也是大多保存在 cookie 里面的),再予以授权的。所以要伪造用户的正常操作,最好的方法是通过 XSS 或链接欺骗等途径,让用户在本机(即拥有身份 cookie 的浏览器端)发起用户所不知道的请求。
你可以这样来理解:
攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。 如下:其中Web A为存在CSRF漏洞的网站,Web B为攻击者构建的恶意网站,User C为Web A网站的合法用户。
CSRF攻击攻击原理及过程如下:
- 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;
- 在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;
- 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;
- 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;
- 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。
举例:
受害者 Bob 在银行有一笔存款,通过对银行的网站发送请求
http://bank.example/withdraw?account=bob&amount=1000000&for=bob2
可以使 Bob 把 1000000 的存款转到 bob2 的账号下。通常情况下,该请求发送到网站后,服务器会先验证该请求是否来自一个合法的 session,并且该 session 的用户 Bob 已经成功登陆。
黑客 Mallory 自己在该银行也有账户,他知道上文中的 URL 可以把钱进行转帐操作。Mallory 可以自己发送一个请求给银行:
http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory
。
但是这个请求来自 Mallory 而非 Bob,他不能通过安全认证,因此该请求不会起作用。
这时,Mallory 想到使用 CSRF 的攻击方式,他先自己做一个网站,在网站中放入如下代码:
src=”http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory ”
,并且通过广告等诱使 Bob 来访问他的网站。当 Bob 访问该网站时,上述 url 就会从 Bob 的浏览器发向银行,而这个请求会附带 Bob 浏览器中的 cookie 一起发向银行服务器。大多数情况下,该请求会失败,因为他要求 Bob 的认证信息。但是,如果 Bob 当时恰巧刚访问他的银行后不久,他的浏览器与银行网站之间的 session 尚未过期,浏览器的 cookie 之中含有 Bob 的认证信息。这时,悲剧发生了,这个 url 请求就会得到响应,钱将从 Bob 的账号转移到 Mallory 的账号,而 Bob 当时毫不知情。等以后 Bob 发现账户钱少了,即使他去银行查询日志,他也只能发现确实有一个来自于他本人的合法请求转移了资金,没有任何被攻击的痕迹。而 Mallory 则可以拿到钱后逍遥法外。
防范CSRF
(1)验证 HTTP Referer 字段,利用 HTTP 头中的 Referer 判断请求来源是否合法,Referer记录了该 HTTP 请求的来源地址。
优点:简单易行,只需要在最后给所有安全敏感的请求统一增加一个拦截器来检查 Referer 的值就可以。特别是对于当前现有的系统,不需要改变当前系统的任何已有代码和逻辑,没有风险,非常便捷。
缺点:Referer 的值是由浏览器提供的,不可全信,低版本浏览器下 Referer 存在伪造风险。用户自己可以设置浏览器使其在发送请求时不再提供 Referer 时,网站将拒绝合法用户的访问。
(2)在请求地址中添加 token 并验证。CSRF 攻击之所以能够成功,是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证。要抵御CSRF,关键在于在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token,如果请求中没有 token 或者 token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。
优点:这种方法要比检查 Referer 要安全一些,token 可以在用户登陆后产生并放于 session 之中,然后在每次请求时把 token 从 session 中拿出,与请求中的 token 进行比对。
缺点:对所有请求都添加 token 比较困难。难以保证 token 本身的安全,依然会被利用获取到 token。
(3)在 HTTP 头中自定义属性并验证
这种方法也是使用 token 并进行验证,和上一种方法不同的是,这里并不是把 token 以参数的形式置于 HTTP 请求之中,而是把它放到 HTTP 头中自定义的属性里。通过 XMLHttpRequest 这个类,可以一次性给所有该类请求加上 csrftoken 这个 HTTP 头属性,并把 token 值放入其中。这样解决了上种方法在请求中加入 token 的不便,同时,通过 XMLHttpRequest 请求的地址不会被记录到浏览器的地址栏,也不用担心 token 会透过 Referer 泄露到其他网站中去。
优点:统一管理 token 输入输出,可以保证 token 的安全性。
缺点:有局限性,无法在非异步的请求上实施。
面试题点
明确 xss和csrf是什么
明确xss和 csrf攻击的特点
如何防范xss和csrf攻击
回答思路
首先明确 xss(Cross Site Scripting )是跨站脚本攻击 csrf(Cross-site request forgery)是跨站请求伪造, 然后分别举一下两种攻击的例子,最后谈下两种攻击的防范措施。
相关扩展
- XSS 和 CSRF简述及预防措施
- 服务器受到DDoS攻击
关注公众号:程序员石磊 获取更多前端面试题
最后
以上就是自觉柠檬为你收集整理的2021前端面试题系列:fetch与axios、浏览器内多个标签页面通信及安全问题fetch与axios浏览器内多个标签页之间的通讯XSS、CSRF 以及如何防范的全部内容,希望文章能够帮你解决2021前端面试题系列:fetch与axios、浏览器内多个标签页面通信及安全问题fetch与axios浏览器内多个标签页之间的通讯XSS、CSRF 以及如何防范所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复