我正在开发一个纯粹在 JavaScript 中的 OAuth 身份验证流程,我想在弹出窗口中向用户显示“授予访问权限”窗口,但它被阻止了。
如何防止由任何一个创建的弹出窗口window.open
或被window.showModalDialog
不同浏览器的弹出窗口阻止程序阻止?
我正在开发一个纯粹在 JavaScript 中的 OAuth 身份验证流程,我想在弹出窗口中向用户显示“授予访问权限”窗口,但它被阻止了。
如何防止由任何一个创建的弹出窗口window.open
或被window.showModalDialog
不同浏览器的弹出窗口阻止程序阻止?
一般规则是,如果从不是由直接用户操作window.open
调用的 javascript 调用或类似调用,则弹出窗口阻止程序将参与。也就是说,您可以调用以响应按钮单击而不会被弹出阻止程序击中,但如果您将相同的代码放入计时器事件中,它将被阻止。调用链的深度也是一个因素 - 一些较旧的浏览器只查看直接调用者,较新的浏览器可以回溯一点以查看调用者的调用者是否是鼠标点击等。保持尽可能浅以避免弹出窗口阻止程序。window.open
基于Jason Sebring的非常有用的提示,以及这里和那里所涵盖的内容,我为我的案例找到了一个完美的解决方案:
带有 Javascript 片段的伪代码:
立即在用户操作上创建一个空白弹出窗口
var importantStuff = window.open('', '_blank');
window.open
(使用您需要的任何其他选项来丰富调用。)
可选:添加一些“等待”信息消息。例子:
a) 外部 HTML 页面:将上面的行替换为
var importantStuff = window.open('http://example.com/waiting.html', '_blank');
b) 文本:在上面一行下面添加以下行:
importantStuff.document.write('Loading preview...');
准备好后用内容填充它(例如,当返回 AJAX 调用时)
importantStuff.location.href = 'https://example.com/finally.html';
或者,如果您根本不需要它,您可以在此处关闭窗口(if ajax request fails
例如 - 感谢@Goose 的评论):
importantStuff.close();
实际上,我将此解决方案用于 mailto 重定向,它适用于我的所有浏览器(Windows 7、Android)。顺便说一句,该_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="_blank"
:如果弹出窗口成功打开,返回false
将阻止链接动作,否则如果弹出窗口被阻止,返回true
将让默认行为(打开新的_blank窗口)并继续.
<a href="http://whatever.com" target="_blank" onclick='return pop("http://whatever.com",300,200);' >
这样,如果它有效,您将有一个弹出窗口,如果没有,您将有一个 _blank 窗口。
如果弹出窗口未打开,您可以:
除了瑞士先生的帖子,在我的情况下,window.open是在一个承诺中启动的,它打开了弹出窗口阻止程序,我的解决方案是:在角度:
$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;
}
这就是您可以使用承诺响应而不调用弹出窗口阻止程序来打开新选项卡的方法。
http://code.google.com/p/google-api-javascript-client/wiki/Authentication
查看上面写着的区域:
设置身份验证
OAuth 2.0 的客户端实现使用弹出窗口提示用户登录并批准应用程序。第一次调用 gapi.auth.authorize 可以触发弹出窗口阻止程序,因为它会间接打开弹出窗口。要防止弹出窗口阻止程序在 auth 调用上触发,请在客户端加载时调用 gapi.auth.init(callback)。当库准备好进行身份验证调用时,将执行提供的回调。
我猜它与上面的真实答案有关,它如何解释是否有立即响应,它不会触发弹出警报。“gapi.auth.init”正在制作它,因此 api 立即发生。
实际应用
我使用 npm 上的节点护照和每个提供商的各种护照包创建了一个开源身份验证微服务。我对第 3 方使用了标准重定向方法,给它一个重定向 URL 以返回。这是程序化的,所以如果登录/注册和特定页面,我可以有不同的位置重定向回。
我尝试了多种解决方案,但他是唯一在所有浏览器中真正为我工作的解决方案
let newTab = window.open();
newTab.location.href = url;
我的用例:在我的反应应用程序中,用户单击后,会对后端执行 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 填充选项卡并跳过弹出窗口阻止程序。
@here 我发现它在所有浏览器中都可以正常工作
window.open(URL) || window.location.assign(URL)
只需使用window.location.href = yourUrl
或带有的网址target='_blank'
window.open()
有太多问题,如果距离用户操作超过一秒,许多浏览器会将其视为弹出窗口并阻止它
除非回调成功返回,否则我不想创建新页面,所以我这样做是为了模拟用户点击:
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);
});
}
摆脱这种情况的最简单方法是:
前任 :
<script>
function loadUrl(location)
{
this.document.location.href = location;
}</script>
<div onclick="loadUrl('company_page.jsp')">Abc</div>
这对我来说效果很好。干杯