避免浏览器popup式窗口拦截器

我正在开发纯粹的JavaScript的OAuth身份validationstream程,我想在popup窗口中显示用户的“授予访问”窗口,但它被阻止。

如何防止由window.openwindow.showModalDialog创build的window.showModalDialog被不同浏览器的popup窗口阻止?

一般的规则是,如果window.open或类似的javascript调用不被直接的用户操作调用,popup式窗口拦截器将参与window.open 。 也就是说,你可以调用window.open来响应button的点击,而不会被popup窗口拦截器击中,但是如果你把相同的代码放在一个定时器事件中,它将被阻塞。 深度调用链也是一个因素 – 一些较旧的浏览器只查看直接调用者,较新的浏览器可以稍微回溯一下,看看调用者的调用者是否是鼠标点击等。尽可能避免popup窗口阻止程序。

根据Jason Sebring的非常有用的提示 ,以及在这里和那里覆盖的东西(无论人们告诉你什么关于w3schools – 谷歌机器人喜欢他们…),我find了一个完美的解决scheme:

伪代码与JavaScript片段:

  1. 立即在用户操作上创build一个空白popup框

     var importantStuff = window.open('', '_blank'); 

    可选:添加一些“等待”信息消息。 例子:

    a)一个外部的HTML页面:用上面的行代替

     var importantStuff = window.open('http://example.com/waiting.html', '_blank'); 

    b)文本:在上面添加下面一行:

     importantStuff.document.write('Loading preview...'); 
  2. 准备好时填充内容(例如,返回AJAX调用时)

     importantStuff.location.href = 'http://shrib.com'; 

使用任何其他选项丰富对window.open的调用。

我实际上使用这个解决scheme进行mailtoredirect,它可以在我的所有浏览器(Windows 7,Android)上运行。 _blank位有助于mailtoredirect在移动工作,顺便说一句。

你的经验? 任何方式来改善这一点?

作为一个良好的做法,我认为testing一个popup窗口是否被阻止并采取行动是个好主意。 你需要知道window.open有一个返回值,如果操作失败,该值可能为空。 例如,在以下代码中:

 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; } 

如果popup窗口被阻止,window.open将返回null。 所以函数将返回false。

例如,想象一下直接从target="_blank"任何链接调用这个函数:如果popup菜单被成功打开,返回false将阻止链接动作,否则如果popup窗口被阻止,返回true将使默认行为(打开新的_blank窗口)并继续。

 <a href="http://whatever.com" target="_blank" onclick='return pop("http://whatever.com",300,200);' > 

这样,如果它有效,你将会popup一个窗口,如果没有则popup一个_blank窗口。

如果popup窗口没有打开,您可以:

  • 打开一个像例子中的空白窗口,然后继续
  • 打开一个假的popup窗口(页面内的iframe)
  • 通知用户(“请允许popup此网站”)
  • 打开一个空白的窗口,然后通知用户等。

来自Google的oauth JavaScript API:

http://code.google.com/p/google-api-javascript-client/wiki/Authentication

看到它所在的区域:

设置身份validation

客户端的OAuth 2.0实现使用popup窗口来提示用户login并批准应用程序。 对gapi.auth.authorize的第一次调用可以触发popup窗口阻止程序,因为它间接打开了popup窗口。 要防止popup窗口阻止程序在auth调用上触发,请在客户端加载时调用gapi.auth.init(callback)。 当库准备好validation呼叫时,提供的callback将被执行。

我猜想它与上面的真实答案有关,如何解释是否有即时的响应,它不会跳出popup报警。 “gapi.auth.init”正在使api立即发生。

实际应用

我使用npm上的节点护照和每个提供者的各种护照包制作了一个开源authentication微服务。 我使用标准的redirect方法给第三方,给它一个redirect的URL来回来。 这是程序化的,所以我可以有不同的地方redirect,如果login/注册和特定页面。

github.com/sebringj/athu

passportjs.org

另外瑞士先生的post,在我的情况下, window.open启动里面的一个承诺,打开popup窗口拦截器,我的解决scheme是:在angular:

 $scope.gotClick = function(){ var myNewTab = browserService.openNewTab(); someService.getUrl().then( function(res){ browserService.updateLocation(res.url, myNewTab); } ); }; 

browserService:

 this.openNewTab = function(){ var newTabWindow = $window.open(); return newTabWindow; } this.updateTabLocation = function(tabLocation, tab) { if(!tabLocation){ tab.close(); } tab.location.href = tabLocation; } 

这是如何使用promise响应打开一个新选项卡,而不是调用popup窗口阻止程序。

我不想做新的页面,除非callback成功返回,所以我做了这个模拟用户点击:

 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); }); } 

摆脱这个最简单的方法是,这对我很好 –

  1. 不要使用document.open()。
  2. 而是使用this.document.location.href = location; 其中位置是要加载的url

例如:

 <script> function loadUrl(location) { this.document.location.href = location; }</script> <div onclick="loadUrl('company_page.jsp')">Abc</div> 

这工作得很好。 干杯