ブラウザのポップアップブロッカーを回避する


172

私は純粋にJavaScriptでOAuth認証フローを開発しており、ユーザーにポップアップで「アクセス許可」ウィンドウを表示したいのですが、ブロックされます。

によって作成されたポップアップウィンドウ、window.openまたはwindow.showModalDialog別のブラウザーのポップアップブロッカーによってブロックされないようにするにはどうすればよいですか?


11
可能だったとしても(わかりません)、ポップアップブロッカーを使用している場合は、それを尊重する必要があります。ほとんどのブラウザは、サイトがポップアップを開こうとしたときにメッセージを表示するため、必要に応じてポップアップを表示できます。一部のコンテンツがポップアップで開き、ユーザーが続行するためにそれを許可する必要があることをサイトにコメントすることができます。
Felix Kling

5
ベストプラクティスは次のようになります。1)これを正常に実行します。2)窓を閉め、ドアを遮断し、動揺するWeb常連客の群衆からの恐れを恐れます。3)悔い改め、ポップアップバスタバスタを取り除き、尊重します。あなたの聴衆。
Alex Mcp 2010

アレックスとフェリックス、質問を更新しました。私は悪の知識を使用しません:)。ありがとう!
Pablo Fernandez

9
追加したいのは、ポップアップブロッカーをバイパスすることで、実際にユーザーエクスペリエンスを改善しようとしている可能性があることです。私が現在取り組んでいる例では、(ExtJSに基づく)Javascriptアプリケーションを使用しており、ユーザーにpaypalを使用した支払いを許可しようとしています。新しいウィンドウでPayPalを起動するためにクリックできるボタンを提供していますが、IEの特定のバージョンでは(ボタンクリックであっても)ポップアップとしてブロックされます。ポップアップを有効にすると、画面がリロードされ、JavaScriptアプリとしてウィンドウの状態が失われるため、最初からやり直す必要があります。だから本当に:問題はIEがばかげていることです。
NateDSaint

1
@FelixKlingはい、可能です。ブラウザメーカーはすでにこれについて考えていました。ユーザーの意図(リンクまたはボタンをクリックすることで通知される)がある限り、ポップアップを開いても問題ありません。ポップアップブロッカーは、ユーザーの意図を尊重する必要があります。IEのポップアップブロッカーがそうでない場合は、障害のあるのはポップアップブロッカーです。ユーザーはポップアップブロッカーを使用して、スクリプトがポップアップを思い通りに開かないようにします。自分で開こうとしたポップアップを(ボタンまたはリンクをクリックして)ブロックするためではありません。
Stijn de Witt 2017

回答:


286

一般的なルールは、直接のユーザーアクションwindow.openによって呼び出されないJavaScriptから、または同様のものが呼び出された場合、ポップアップブロッカーが関与することです。つまり、ポップアップブロッカーにヒットすることなくボタンのクリックに応答して呼び出すことができますが、タイマーイベントに同じコードを配置すると、ブロックされます。呼び出しチェーンの深さも要因です。一部の古いブラウザーは、直接の呼び出し元のみを確認します。新しいブラウザーは、少し戻って、呼び出し元の呼び出し元がマウスクリックであったかどうかを確認できます。ポップアップブロッカーを避けるために、できるだけ浅くしてください。window.open


2
興味深いことに、select要素にバインドされたchangeイベントを通じて開始されたポップアップは、クリックなどの直接的なユーザーアクションによって開始されたとしても、ブロックされます(FFではなくChromeで)。ただし、入力にバインドされている場合は許可されます。奇妙な。
ccnokes 2014

6
ブラウザに一貫性があると言った人はいません。:P
dthorpe 2014

8
実験を通して、スタックの深さはポップアップブロッカーとは何の関係もないことを理解しなければなりません。ユーザーのアクション後1秒以内にwindow.openが呼び出されるかどうかを実際に確認します。Chrome 46とFirefox 42でテスト済み
Mesqalito

1秒のタイムアウトは両方のブラウザーで回避でき、このページの @ tj-crowderによる回答を使用して無期限に時間を確保できます。ajax経由で呼び出すURLに、sleep()を使用するphp(またはその他)を指定します。 )応答を返すまでの時間。ブラウザがページを「ロード」している間、ブラウザはハングします。次に、応答を受信したときにポップアップをトリガーします。ただし、Chromeでは、このトリックを機能させるために、ajax()の直前にalert()を追加する必要があります。
ファンファーレ

184

Jason Sebring非常に便利なヒントとあちこちで取り上げられていることに基づいて、私の場合に最適な解決策を見つけました。

JavaScriptスニペットを使用した疑似コード:

  1. ユーザーアクションですぐに空白のポップアップを作成する

    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必要な追加オプションを使用して、への通話を充実させます。

私は実際にこのソリューションをmailtoリダイレクトに使用し、すべてのブラウザー(windows 7、Android)で動作します。この_blankビットは、mailtoリダイレクトがモバイルで機能するのに役立ちます。

あなたの経験?これを改善する方法はありますか?


1
?それで、ブラウザでのユーザーアクションからでない場合はどうしますか?私の例では、ユーザーがサーバーに対して認証した後、新しいタブを開く必要があります
Don Cheadle

@mmcraeはそれをしません。何をするつもりでも、ポップアップウィンドウよりも良い方法があります。さもなければ、私はあなたのサイトを見たくないでしょう。今日のブラウザは、それを実行できないようにする必要があります。@ dthorpeの回答を参照してください。
スイスミスター

5
Whatever it is you intend to do, there is a better way than a popup window笑?奇妙な一般化。クライアントは、認証したページを開いたままにし、認証後の新しいサイト/ランディングページを新しいタブで開くことを望んでいます。はい、優れたユーザーエクスペリエンスについての私の考えではありません...しかしそれは妥当なようです
Don Cheadle

@mmcrae。真剣に座って考えてください。あなたが説明するシナリオで「ユーザーアクション」を見つけることを約束します。私の答えの要点は、ユーザーアクションがあるときにポップアップウィンドウを作成し、後でコンテンツを入力することです。あなたのケースのヒント:ユーザーが「認証」を押す->ポップアップを作成します(空); タイマーがアップしているか、サーバーの応答が戻っているか、何でも->ポップアップにコンテンツを入力します。
スイスミスター

3
役立つヒント、ajaxリクエストが失敗した場合は、を呼び出しimportantStuff.closeて新しいタブを閉じ、元のページに警告を表示します。
グース

24

さらに、スイスミスターの投稿、私の場合、window.openは、ポップアップブロッカーをオンにするpromise内で起動されました。私の解決策は次のとおりです。

$scope.gotClick = function(){

  var myNewTab = browserService.openNewTab();
  someService.getUrl().then(
    function(res){
        browserService.updateTabLocation(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応答を使用してポップアップブロッカーを呼び出さずに新しいタブを開く方法です。


1
これが私の解決策につながりました!開いたタブを含む変数を作成し、データが読み込まれた後にURLを入力しました。ありがとう。const tab = window.open(); observable.subscribe(dataUrl => tab.location.href = dataUrl);
ジョナス

1
ポップアップブロッカーを有効にしている場合、ポップアップブロッカーの問題は解決されません...
Alejandro Vales

@Alejandro Vales jonasソリューションが機能するのは、コードがonClickイベント、またはユーザーインタラクションから実行される場合のみです。promise、timeout、subscribeの内部でwindows.openを介して新しいタブを開こうとすると、ブラウザーはそれがユーザーの操作であると考えます。そのため、解決策は、promiseに入る前にインスタンスを作成し、変更するだけです。ジョナスのようなhref
デビッド

@Davidありがとうございます!!! 私は.thenその時の答えを見ることはありませんでした、そしてそれが私がとても混乱した理由です:/ SRY ...
Alejandro Vales

@Davidこれは素晴らしい!魅力のように機能します。もう1つだけ質問してもらえれば、これをEdgeでも機能させる方法を知っていますか?適切なリソースへのナッジは大いに役立ちます...
dzenesiz 2018

21

良い方法として、ポップアップがブロックされたかどうかをテストし、万が一に備えてアクションを実行することをお勧めします。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ウィンドウが表示されます。

ポップアップが開かない場合は、次のことができます。

  • 例のように空白のウィンドウを開いて続行します
  • 偽のポップアップを開く(ページ内のiframe)
  • ユーザーに通知する(「このサイトのポップアップを許可してください」)
  • 空白のウィンドウを開き、ユーザーに通知します。

ありがとうございました。働いた!
Bcktr

8

Googleのoauth JavaScript APIから:

http://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のノードパスポートと各プロバイダーのさまざまなパスポートパッケージを使用して、オープンソース認証マイクロサービスを作成しました。私はサードパーティに標準のリダイレクトアプローチを使用して、リダイレクトURLを返しました。これはプログラマティックだったので、ログイン/サインアップの場合や特定のページにリダイレクトするために別の場所を使用することができました。

github.com/sebringj/athu

passportjs.org


3

私は複数の解決策を試しましたが、実際にすべてのブラウザで機能したのは彼だけです

let newTab = window.open(); newTab.location.href = url;


2
これは、ポップアップブロッカーが有効になっているユーザーには機能しません
Alejandro

なにurl?割り当てられていません。
shinriyo

@shinriyo URLは、たとえば、アクセスに好きなページへのリンクですhttp://example.com
pomobc

@AlejandroValesポップアップブロッカーを有効にして動作します。問題は、window.open()プログラムで新しいウィンドウを開くことができず、必要に応じてその答えが選択肢の1つになることです。ではnewTab、変数我々はへの参照を作成window.open()し、後で私たちは、INSERT、それを呼び出すことができますurlいくつかのブロブの私の場合のURLには、私たちの必要性、および新しいタブが入力されたURL上で開かれます。
stanimirsp

0

コールバックが正常に返されない限り、新しいページを作成したくなかったので、ユーザーのクリックをシミュレートするためにこれを行いました。

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

3
Chrome 62では動作しません。ポップアップ(ページ)がブロックされます。
s.ermakovich 2017

1
はい、そうです。これにも一貫性がないことがわかりました。私は私のAPI呼び出し同期作ってしまった
user3479425

-8

これを取り除く最も簡単な方法は、次のとおりです。

  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>

これは私にとって非常にうまくいきました。乾杯


2
新しいタブでURLを開くのはどうですか?
3つのルール
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.