新开窗口的那些事:拦截、安全、target

简介: 前端开发经常会遇到需要新开窗口的需求,而某些时候,新窗口的地址需要通过接口返回,经常就会遇到新开窗口被拦截的情况,这里说一下新开窗口的几种方式、被拦截的原因以及如何避免被拦截、新窗口安全、target 的秘密。

网络异常,图片无法展示
|

前端开发经常会遇到需要新开窗口的需求,而某些时候,新窗口的地址需要通过接口返回,经常就会遇到新开窗口被拦截的情况,这里说一下新开窗口的几种方式、被拦截的原因以及如何避免被拦截、新窗口安全、target 的秘密。

方式

主流的新开方式分为两种:

window.open

window.open 也是比较常用的一种弹窗方式,可以直接脚本打开新窗口,且可控制窗口是否弹出、大小等。

window.open(url, name, features);
复制代码

模拟 a 标签

第三种方式是创建一个 a 标签,然后通过触发它的点击事件来打开新窗口,也算是比较常用的方式。

const openLink = (link: string) => {
    const a = document.createElement('a');
    a.href = link;
    a.target = '_blank';
    a.click();
};
复制代码

除了上述几种常用方式,还有可以使用弹窗提示用户再次点击跳转、预先请求链接完成后再渲染按钮等,这里不做讨论。

拦截和避免

然而无论是 window.open 还是模拟 a 标签点击,都会遇到被拦截的情况,原因是很多黑产滥用弹窗功能,导致浏览器对这块功能收紧,当浏览器弹窗不是由用户发起时,便会拦截该操作。那浏览器是怎么判定是否由用户发起的呢?其实是当用户进行了点击行为一段时间内,浏览器都会认为该操作是用户的行为。并且该时间段内只能触发一次合法弹窗,多次弹窗依旧会被拦截。同时如果该时间段内触发的 setTimeout,会以 setTimeout 调用的时间为准,即只需要 setTimeout 在指定时间内调用,而不管 setTimeout 中的 window.open 或模拟点击的时间。

通过上面的分析,我们可以知道,如果用户点击后,一段时间内还没拿到 url 进行新窗口打开的操作,浏览器就会进行拦截,这个时间段各浏览器中好像并不一致。

通过上面的信息,为了避免被拦截,可以想到以下方案:

通过 setTimeout 定时一段足够请求返回的时间段,获取请求到的数据,打开新窗口,这种方式过于死板,不推荐。

在点击后直接打开窗口,然后等待请求返回后,再将新窗口重定向到返回的地址,这也是使用最为广泛的方式。

const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
const getUrl = async () => {
    await sleep(1000);
    return 'https://www.baidu.com';
};
const newWindow = window.open('about:blank', '_blank');
newWindow.location.href = await getUrl();
复制代码

不过该方式体验上也有点问题,因为打开窗口触发后窗口便会弹出,而等待请求的这段时间里该窗口都会是一片空白,还有接口报错后窗口依旧保留,这里可以做一些小小的优化。

const newWindow = window.open('about:blank', '_blank');
newWindow.document.write('waiting...');
try {
    newWindow.location.href = await getUrl();
} catch (error) {
    newWindow.close();
    alert('open failed');
}
复制代码

其它的还有通过将请求改为同步请求等方式,这里不做讨论。

安全

通过 window.open 或者 a 链接打开的标签可以通过 window.opener 拿到原页面的 window 引用,如果新窗口为外部页面,可能会导致信息泄漏、被钓鱼等安全问题。为了避免该情况,需要在 a 标签中添加 rel='noopener'rel='noreferrer',在 window.open 中添加 noopenernoreferrerfeatures

注意 noreferrer 包含 noopener 的作用,并且会影响到窗口请求的 referrer 头,会影响到一些导流分析统计数据。

不过经测试最新 chrome 中使用 a 标签点击时,opener 默认为 null,必须要显示使用 rel='opener' 才能拿到 opener 引用。

target

在打开窗口时我们也经常用到 target,一般包含四个内置值:

  • _self 当前窗口打开
  • _blank 新窗口打开
  • _parent 父窗口打开,iframe 的父窗口
  • _top 顶层窗口,同样是 iframe 中的最顶层窗口

其实除了这几个常用值,target 还可以为任何字符串,该字符串会作为窗口的名称也就是 window.name,如果存在同名窗口,则会在对应窗口中打开链接,如果不存在则会创建一个新窗口。

当某些窗口全局只能存在一个时,该属性会非常有效,比如登陆页面,可以设置其 namemy_login,当在其它页面需要登录时,直接将 target 设置为 my_login,就可以直接进入登陆页面,避免用户打开一堆新窗口。

相关文章
|
前端开发
前端Vue3使用Moment Timezone处理不同时区时间
认识基本时间表示字符,UTC,GMT等,用 moment-timezone 这个插件来获取时区,同时获取带时区的时间字段,以便后续业务处理。
966 1
|
敏捷开发 前端开发 JavaScript
No148.精选前端面试题,享受每天的挑战和学习
No148.精选前端面试题,享受每天的挑战和学习
|
存储 SQL 分布式数据库
OceanBase 入门:分布式数据库的基础概念
【8月更文第31天】在当今的大数据时代,随着业务规模的不断扩大,传统的单机数据库已经难以满足高并发、大数据量的应用需求。分布式数据库应运而生,成为解决这一问题的有效方案之一。本文将介绍一款由阿里巴巴集团自主研发的分布式数据库——OceanBase,并通过一些基础概念和实际代码示例来帮助读者理解其工作原理。
1095 0
|
数据采集 Python
揭秘淘宝商品信息:Python爬虫技术入门与实战指南
Python爬虫用于获取淘宝商品详情,依赖`requests`和`beautifulsoup4`库。安装这两个库后,定义函数`get_taobao_product_details`,发送GET请求模拟浏览器,解析HTML获取标题和价格。注意选择器需随页面结构更新,遵守爬虫政策,控制请求频率,处理异常,且数据只能用于合法目的。
|
Python 数据采集 安全
淘宝商品评论数据爬取:Python实战指南
淘宝商品评论数据的自动爬取可以为市场分析和用户行为研究提供宝贵的信息资源。然而,这一过程需要严格遵守法律法规,尊重数据的版权和隐私。通过合理利用Python的网络爬虫技术,可以在遵循道德规范的前提下,高效地完成数据采集任务。 通过本文的指南,希望你能对淘宝商品评论数据的爬取有一个清晰的认识,并能够安全、合法地进行数据采集。
|
Web App开发 JavaScript 前端开发
Web 页面性能衡量指标-以用户为中心的性能指标
Web 页面性能衡量指标-以用户为中心的性能指标 以用户为中心的性能指标是理解和改进站点体验的关键点 一、以用户为中心的性能指标 1. 指标是用来干啥的? 指标是用来衡量性能和用户体验的 2. 指标类型 • 感知加载速度:网页可以多快地加载网页中的所有视觉元素并将其渲染到屏幕上 • 加载响应速度:页面加载和执行组件快速响应用户互动所需的 JavaScript 代码的速度 • 运行时响应速度:网页在加载后对用户互动的响应速度 • 视觉稳定性:页面上的元素是否会以用户意想不到的方式发生偏移,是否可能会干扰用户的互动? • 流畅性:过渡和动画是否以一致的帧速率渲染,并在一种状态之间流畅地流动
457 1
|
人工智能 JavaScript 前端开发
Vue / Html 等前台中连续多个空格只显示一个空格的解决方法
Vue / Html 等前台中连续多个空格只显示一个空格的解决方法
|
存储 传感器 SQL
智慧校园系统开发(一)
TK智慧校园管理系统主要用来管理校内学生、老师、班级、年级的相关信息,进行老师和学生信息记录和统计的功能,而这些信息是校园信息化建设的核心基础业务数据。
486 1
|
消息中间件 API RocketMQ
你的RocketMQ消费者组(Consumer Group)在查看时显示为离线,这可能是由于消费者组的状态没有被正确更新
你的RocketMQ消费者组(Consumer Group)在查看时显示为离线,这可能是由于消费者组的状态没有被正确更新【1月更文挑战第10天】【1月更文挑战第49篇】
1934 5