Javascript 避免浏览器弹出窗口拦截器
我正在开发纯JavaScript的OAuth身份验证流,我想在弹出窗口中向用户显示“授权访问”窗口,但它被阻止了Javascript 避免浏览器弹出窗口拦截器,javascript,popup,modal-dialog,popup-blocker,Javascript,Popup,Modal Dialog,Popup Blocker,我正在开发纯JavaScript的OAuth身份验证流,我想在弹出窗口中向用户显示“授权访问”窗口,但它被阻止了 如何防止由window.open或window.showModalDialog创建的弹出窗口被不同浏览器的弹出窗口阻止程序阻止?一般规则是,如果window.open或类似程序是从未被直接用户调用的javascript中调用的,弹出窗口阻止程序将启用行动。也就是说,您可以调用窗口。打开以响应按钮单击,而不会被弹出窗口阻止程序击中,但是如果您在计时器事件中放入相同的代码,它将被阻止。调
如何防止由
window.open
或window.showModalDialog
创建的弹出窗口被不同浏览器的弹出窗口阻止程序阻止?一般规则是,如果window.open
或类似程序是从未被直接用户调用的javascript中调用的,弹出窗口阻止程序将启用行动。也就是说,您可以调用窗口。打开以响应按钮单击,而不会被弹出窗口阻止程序击中,但是如果您在计时器事件中放入相同的代码,它将被阻止。调用链的深度也是一个因素-一些旧浏览器只查看直接调用方,新浏览器可以稍微回溯一点,查看调用方的调用方是否是鼠标点击等。尽可能使其保持浅,以避免弹出窗口阻止程序。来自谷歌的oauth JavaScript API:
请参见以下区域:
设置身份验证
OAuth 2.0的客户端实现使用弹出窗口提示用户登录并批准应用程序。第一次调用gapi.auth.authorize会触发弹出窗口阻止程序,因为它会间接打开弹出窗口。要防止弹出窗口阻止程序在auth调用时触发,请在客户端加载时调用gapi.auth.init(回调)。当库准备好进行身份验证调用时,将执行提供的回调
我猜它与上面的真实答案有关,因为它解释了如果有即时响应,它不会触发弹出警报。“gapi.auth.init”使api立即发生
实际应用
我使用npm上的节点passport和每个提供者的各种passport包制作了一个开源身份验证微服务。我对第三方使用了标准的重定向方法,给它一个重定向URL返回。这是编程的,所以我可以在不同的地方重定向回if登录/注册以及特定页面
基于的,以及所涵盖的内容,我为我的案例找到了一个完美的解决方案:
带有Javascript片段的伪代码:
立即在用户操作时创建一个空白弹出窗口
var importantStuff = window.open('', '_blank');
(丰富对窗口的调用。使用打开。)
可选:添加一些“等待”信息消息。示例:
a) 外部HTML页面:将上面的行替换为
var importantStuff = window.open('http://example.com/waiting.html', '_blank');
b) 文本:在上述行下方添加以下行:
importantStuff.document.write('Loading preview...');
准备好后用内容填充它(例如,当AJAX调用返回时)
或者,如果您根本不需要它,您可以在这里关闭该窗口(例如,如果ajax请求失败,则关闭该窗口)
——感谢@Goose的评论):
实际上,我使用这个解决方案进行邮件重定向,它可以在我所有的浏览器(Windows7,Android)上运行。\u blank
位有助于mailto重定向在移动设备上工作,顺便说一句。作为一种良好做法,我认为最好测试弹出窗口是否被阻止,并在这种情况下采取措施。您需要知道window.open有一个返回值,如果操作失败,该值可能为null。例如,在以下代码中:
function pop(url,w,h) {
n=window.open(url,'_blank','toolbar=0,location=0,directories=0,status=1,menubar=0,titlebar=0,scrollbars=1,resizable=1,width='+w+',height='+h);
if(n==null) {
return true;
}
return false;
}
如果弹出窗口被阻止,window.open将返回null。因此,函数将返回false
例如,想象一下直接从任何链接调用此函数
使用target=“\u blank”
:如果弹出窗口成功打开,则返回
false
将阻止链接操作,否则如果弹出窗口被阻止,
返回true
将使默认行为(opennew\u)为空
(窗户)然后继续
这样,如果工作正常,你会有一个弹出窗口,如果工作正常,你会有一个空白窗口
不是
如果弹出窗口未打开,您可以:
- 打开一个空白窗口,如示例中所示,然后继续
- 打开一个假弹出窗口(页面内的iframe)
- 通知用户(“请允许此站点的弹出窗口”)
- 打开一个空白窗口,然后通知用户
等等
摆脱这种状况的最简单方法是:
- 不要使用document.open()
- 而是使用this.document.location.href=location;其中location是要加载的url
例:
函数loadUrl(位置)
{
this.document.location.href=位置;
}
Abc
这对我很有效。
干杯此外,瑞士先生邮报,在我的例子中,window.open是在一个promise内启动的,它打开了弹出窗口阻止程序,我的解决方案是:
在角度上:
$scope.gotClick = function(){
var myNewTab = browserService.openNewTab();
someService.getUrl().then(
function(res){
browserService.updateTabLocation(res.url, myNewTab);
}
);
};
浏览器服务:
this.openNewTab = function(){
var newTabWindow = $window.open();
return newTabWindow;
}
this.updateTabLocation = function(tabLocation, tab) {
if(!tabLocation){
tab.close();
}
tab.location.href = tabLocation;
}
这就是如何使用promise响应打开新选项卡,而不调用弹出窗口阻止程序。除非回调成功返回,否则我不想创建新页面,因此我这样做是为了模拟用户单击:
function submitAndRedirect {
apiCall.then(({ redirect }) => {
const a = document.createElement('a');
a.href = redirect;
a.target = '_blank';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
}
我尝试了多种解决方案,但他的是唯一一种在所有浏览器中都对我有效的解决方案
让newTab=window.open();
newTab.location.href=url代码>我的用例:在我的react应用程序中,当用户单击时,将执行对后端的API调用。根据响应,打开新选项卡,并将api响应作为参数添加到新选项卡URL(在同一域中)
在我的用例中唯一需要注意的是,接收API响应需要1秒以上的时间。因此,当在新选项卡中打开URL时,会显示弹出窗口阻止程序(如果它处于活动状态)
为了避免上述问题,下面是示例代码
var new_tab=window.open()
axios.get('http://backend-api').then(response=>{
const url="http://someurl"+"?response"
new_tab.location.href=url;
}).catch(error=>{
//catch error
})
小结:创建一个空选项卡(如第1行所示),当API调用完成时,您可以用url填充选项卡并跳过弹出窗口阻止程序。即使可能(我不知道),如果人们使用弹出窗口阻止程序,您也应该尊重它。大多数浏览器在站点试图打开弹出窗口时都会显示一条消息,以便在需要时仍能看到它。你可以在你的网站上写一句话,一些内容会在弹出窗口中打开,用户会
$scope.gotClick = function(){
var myNewTab = browserService.openNewTab();
someService.getUrl().then(
function(res){
browserService.updateTabLocation(res.url, myNewTab);
}
);
};
this.openNewTab = function(){
var newTabWindow = $window.open();
return newTabWindow;
}
this.updateTabLocation = function(tabLocation, tab) {
if(!tabLocation){
tab.close();
}
tab.location.href = tabLocation;
}
function submitAndRedirect {
apiCall.then(({ redirect }) => {
const a = document.createElement('a');
a.href = redirect;
a.target = '_blank';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
});
}
var new_tab=window.open()
axios.get('http://backend-api').then(response=>{
const url="http://someurl"+"?response"
new_tab.location.href=url;
}).catch(error=>{
//catch error
})