我正在纯JavaScript中开发OAuth认证流程,想在弹出窗口中显示“授权访问”窗口,但是该窗口被阻止了。
如何防止使用window.open
或window.showModalDialog
创建的弹出窗口被不同浏览器的弹出窗口拦截器拦截?
我正在纯JavaScript中开发OAuth认证流程,想在弹出窗口中显示“授权访问”窗口,但是该窗口被阻止了。
如何防止使用window.open
或window.showModalDialog
创建的弹出窗口被不同浏览器的弹出窗口拦截器拦截?
一般规则是,如果从非直接用户操作调用的 JavaScript 中调用 window.open
或类似函数,弹出窗口拦截器将会启动。也就是说,你可以在响应按钮单击时调用 window.open
而不会被弹出窗口拦截器拦截,但如果将相同的代码放置在计时器事件中,则会被拦截。调用链的深度也是一个因素 - 一些旧版浏览器只查看直接调用者,而新版浏览器可以向后跟踪一点,以查看调用者的调用者是否是鼠标点击等。尽可能保持浅层次,以避免弹出窗口拦截器。
immediately create a blank popup on user action
var importantStuff = window.open('', '_blank');
(Enrich the call to window.open
with whatever additional options you need.)
Optional: add some "waiting" info message. Examples:
a) An external HTML page: replace the above line with
var importantStuff = window.open('http://example.com/waiting.html', '_blank');
b) Text: add the following line below the above one:
importantStuff.document.write('Loading preview...');
fill it with content when ready (when the AJAX call is returned, for instance)
importantStuff.location.href = 'https://example.com/finally.html';
Alternatively, you could close the window here if you don't need it after all (if ajax request fails
, for example - thanks to @Goose for the comment):
importantStuff.close();
我实际上使用这个解决方案进行mailto重定向,它可以在我所有的浏览器(Windows 7,Android)上工作。顺便说一句,_blank
部分有助于在移动设备上实现mailto重定向。
importantStuff.close
关闭新标签页,并在原始页面中提供警告提示。 - Goose作为一个良好的实践,我认为检测弹出窗口是否被阻止并在必要时采取行动是一个不错的主意。您需要知道 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 是在一个 promise 内部启动的,这使得弹出窗口拦截器被激活。我的解决方案如下:
在 Angular 中:
$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;
}
这是使用承诺响应而不触发弹出窗口拦截器打开新标签页的方法。
const tab = window.open(); observable.subscribe(dataUrl => tab.location.href = dataUrl);
- jonas.then
,所以我很困惑 :/ 对不起... - Alejandro Valeshttp://code.google.com/p/google-api-javascript-client/wiki/Authentication
请看下面这个部分:
设置验证
客户端OAuth 2.0的实现使用弹出窗口提示用户登录和授权应用程序。首次调用gapi.auth.authorize可能会触发弹出拦截器,因为它间接地打开弹出窗口。为了防止弹出拦截器在身份验证调用上触发,当客户端加载时调用gapi.auth.init(callback)。当库准备好进行身份验证调用时,将执行提供的回调。
我猜这个与上面的真实答案有关,因为它解释了如果有立即响应,它不会触发弹出窗口警报。 "gapi.auth.init"使api立即运行。
实际应用
我使用npm上的node passport和各种护照包制作了一个开放源代码的身份验证微服务。我使用标准的重定向方法向第三方提供了一个重定向URL。这是编程方式的,所以我可以在不同的位置重定向回来,如果登录/注册并在特定页面上。
我尝试了多个解决方案,但这是唯一一个在所有浏览器中都实际起作用的。
let newTab = window.open();
newTab.location.href = url;
url
?它没有被赋值。 - shinriyohttp://example.com
。 - pomobcwindow.open()
无法以编程方式打开新窗口,如果需要,该答案是其中之一。使用newTab
变量,我们引用window.open()
,稍后可以调用它,在其中插入所需的url
,在我的情况下是某些blob的url,并且新标签将在输入的url上打开。 - stanimirsp我的使用场景: 在我的React应用中,用户点击后会向后端进行API调用。根据响应,在新标签页中打开,将API响应作为参数添加到新标签页的URL中(在同一域)。
我使用情况中唯一需要注意的是,这个API响应需要1秒以上才能接收到。因此,在打开新标签页时,如果弹出窗口拦截器处于活动状态,则会弹出。
为了规避上述问题,以下是示例代码:
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填充选项卡并跳过弹出窗口拦截器。
@在这里 我发现它在所有浏览器中都能正常工作
window.open(URL) || window.location.assign(URL)
只需使用 window.location.href = 您的Url
或一个带有 target='_blank'
的url
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);
});
}