Vermeiden Sie Browser-Popup-Blocker

172

Ich entwickle einen OAuth-Authentifizierungsablauf ausschließlich in JavaScript und möchte dem Benutzer das Fenster "Zugriff gewähren" in einem Popup anzeigen, das jedoch blockiert wird.

Wie kann ich verhindern, dass Popup-Fenster , die von den Popup-Blockern der verschiedenen Browser erstellt wurden window.openoder window.showModalDialogvon diesen blockiert werden, blockiert werden?

Pablo Fernandez
quelle
11
Selbst wenn es möglich wäre (ich weiß nicht), wenn Leute Popup-Blocker verwenden, sollten Sie es respektieren. Die meisten Browser zeigen eine Nachricht an, wenn eine Site versucht hat, ein Popup zu öffnen, damit sie es weiterhin sehen können, wenn sie möchten. Sie können auf Ihrer Website eine Bemerkung einfügen, dass einige Inhalte in einem Popup geöffnet werden und der Benutzer dies zulassen sollte, um fortzufahren.
Felix Kling
5
Die beste Vorgehensweise würde folgendermaßen aussehen: 1) Machen Sie dies erfolgreich 2) Schließen Sie Ihre Fenster und verriegeln Sie Ihre Tür und kauern Sie vor Angst vor der versammelten Menge verärgerter Web-Gönner. 3) Bereuen Sie, entfernen Sie die Pop-up-Busta-Busta und respektieren Sie Ihr Publikum.
Alex Mcp
Alex und Felix, ich habe die Frage aktualisiert. Ich werde das Wissen nicht für das Böse verwenden :). Vielen Dank!
Pablo Fernandez
9
Ich möchte hinzufügen, dass das Umgehen eines Popup-Blockers möglicherweise tatsächlich versucht, die Benutzererfahrung zu verbessern. In einem Beispiel, an dem ich gerade arbeite, verwenden wir eine Javascript-Anwendung (basierend auf ExtJS) und versuchen, Benutzer mit Paypal bezahlen zu lassen. Wir geben ihnen eine Schaltfläche, auf die sie klicken können, um Paypal in einem neuen Fenster zu starten, aber bestimmte Versionen von IE blockieren es als Popup (obwohl es sich um eine Schaltfläche handelt). Wenn sie jetzt das Popup aktivieren, den Bildschirm neu laden und als JavaScript-App den Fensterstatus verlieren, müssen sie neu beginnen. Also wirklich: Das Problem ist, dass IE dumm ist.
NateDSaint
1
@FelixKling Ja das ist möglich. Browserhersteller haben bereits darüber nachgedacht. Das Öffnen eines Popups ist in Ordnung, sofern eine Benutzerabsicht vorliegt (signalisiert durch Klicken des Benutzers auf einen Link oder eine Schaltfläche). Popup-Blocker sollten die Benutzerabsicht respektieren. Wenn der Popupblocker des IE dies nicht tut, ist der Popupblocker schuld. Benutzer verwenden Popup-Blocker, um zu verhindern, dass Skripte Popups nach Belieben öffnen, und nicht, um Popups zu blockieren, die sie selbst zu öffnen versucht haben (durch Klicken auf eine Schaltfläche oder einen Link).
Stijn de Witt

Antworten:

286

Die allgemeine Regel lautet, dass Popup-Blocker aktiviert werden, wenn window.openoder ähnliches aus Javascript aufgerufen wird, das nicht durch direkte Benutzeraktionen aufgerufen wird . Das heißt, Sie können als window.openReaktion auf einen Tastenklick aufrufen, ohne vom Popup-Blocker getroffen zu werden. Wenn Sie jedoch denselben Code in ein Timer-Ereignis einfügen, wird dieser blockiert. Die Tiefe der Anrufkette ist ebenfalls ein Faktor - einige ältere Browser sehen nur den unmittelbaren Anrufer an, neuere Browser können ein wenig zurückverfolgen, um festzustellen, ob der Anrufer des Anrufers ein Mausklick war usw. Halten Sie ihn so flach wie möglich, um Popup-Blocker zu vermeiden.

dthorpe
quelle
2
Interessanterweise werden Popups, die durch ein an ein ausgewähltes Element gebundenes Änderungsereignis ausgelöst wurden, blockiert (in Chrome, nicht in FF), obwohl dieses Ereignis durch eine direkte Benutzeraktion wie einen Klick ausgelöst wird. Obwohl sie an eine Eingabe gebunden sind, sind sie zulässig. Seltsam.
ccnokes
6
Niemand sagte, der Browser sei konsistent. : P
dthorpe
8
Durch Experimente muss ich verstehen, dass die Stapeltiefe nichts mit Popupblocker zu tun hat. Es wird tatsächlich geprüft, ob window.open innerhalb von 1 Sekunde nach der Benutzeraktion aufgerufen wird oder nicht. Getestet in Chrome 46 und Firefox 42.
Mesqalito
Das 1-Sekunden-Timeout kann in beiden Browsern umgangen werden, wobei eine unbegrenzte Zeitspanne mit der Antwort von @ tj-crowder auf dieser Seite möglich ist . ) für eine gewisse Zeit, bevor eine Antwort zurückgegeben wird. Der Browser bleibt hängen, während die Seite "geladen" wird. Anschließend wird das Popup ausgelöst, wenn eine Antwort eingeht. In Chrome müssen Sie jedoch direkt vor ajax () eine Warnung () hinzufügen, damit dieser Trick funktioniert.
Fanfare
184

Basierend auf Jason Sebring ‚s sehr nützlichen Tipp , und auf dem Material bedeckt hier und dort fand ich eine perfekte Lösung für meinen Fall:

Pseudocode mit Javascript-Schnipsel:

  1. Erstellen Sie sofort ein leeres Popup für Benutzeraktionen

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

    Optional: Fügen Sie eine wartende Info-Nachricht hinzu. Beispiele:

    a) Eine externe HTML-Seite: Ersetzen Sie die obige Zeile durch

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

    b) Text: Fügen Sie die folgende Zeile unter der obigen ein:

    importantStuff.document.write('Loading preview...');
  2. Füllen Sie es mit Inhalt, wenn Sie bereit sind (z. B. wenn der AJAX-Aufruf zurückgegeben wird).

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

Bereichern Sie den Anruf window.openmit den zusätzlichen Optionen, die Sie benötigen.

Ich verwende diese Lösung tatsächlich für eine Mailto-Umleitung und sie funktioniert in allen meinen Browsern (Windows 7, Android). Das _blankBit hilft übrigens dabei, dass die Mailto-Umleitung auf Mobilgeräten funktioniert.

Deine Erfahrung? Wie kann man das verbessern?

Schweizer Herr
quelle
1
? Was machen Sie also, wenn es sich nicht um eine Benutzeraktion im Browser handelt? In meinem Beispiel muss der Benutzer nach der Authentifizierung gegenüber dem Server einen neuen Tab öffnen
Don Cheadle
@mmcrae mach das nicht. Was auch immer Sie vorhaben, es gibt einen besseren Weg als ein Popup-Fenster. Andernfalls würde ich Ihre Website wahrscheinlich nie sehen wollen. Die heutigen Browser stellen sicher, dass Sie dies nicht können sollten - siehe die Antwort von @dthorpe .
Schweizer Herr
5
Whatever it is you intend to do, there is a better way than a popup windowlol? Seltsame Verallgemeinerung. Der Client möchte, dass die Seite, auf der er sich authentifiziert hat, geöffnet bleibt und die neue Site / Zielseite nach der Authentifizierung in einem neuen Tab geöffnet wird. Ja, nicht meine Vorstellung von einer hervorragenden Benutzererfahrung ... aber es scheint vernünftig
Don Cheadle
@mmcrae. Setzen Sie sich und denken Sie ernsthaft nach. Ich verspreche Ihnen, dass Sie in dem von Ihnen beschriebenen Szenario eine "Benutzeraktion" finden werden. Der springende Punkt meiner Antwort ist, dass Sie das Popup-Fenster erstellen, wenn Sie die Benutzeraktion ausführen - und es später mit Inhalten füllen. Hinweis für Ihren Fall: Benutzer drückt auf "Authentifizieren" -> Popup erstellen (leer); Der Timer ist abgelaufen oder die Serverantwort ist zurück oder was auch immer -> Füllen Sie den Inhalt in das Popup.
Schweizer Herr
3
Nützlicher Tipp: Wenn die Ajax-Anforderung fehlschlägt, rufen Sie importantStuff.closean, um die neue Registerkarte zu schließen und auf der Originalseite eine Benachrichtigung bereitzustellen.
Gans
24

Zusätzlich zum Swiss Mister Post, in meinem Fall wurde window.open innerhalb eines Versprechens gestartet, das den Popup-Blocker einschaltete. Meine Lösung war: in eckig:

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

Auf diese Weise können Sie mithilfe der Versprechen-Antwort einen neuen Tab öffnen und den Popup-Blocker nicht aufrufen.

David
quelle
1
Dies führte zu meiner Lösung! Wo ich eine Variable erstellt habe, die die geöffnete Registerkarte enthält, und dann die URL gefüllt habe, nachdem die Daten geladen wurden. Vielen Dank. const tab = window.open(); observable.subscribe(dataUrl => tab.location.href = dataUrl);
Jonas
1
Wenn Sie den Popup-Blocker aktiviert haben, wird das Problem mit dem Popup-Blocker nicht behoben ...
Alejandro Vales
Die Jonas-Lösung von @Alejandro Vales funktioniert nur, wenn der Code von einem onClick-Ereignis oder einer Benutzerinteraktion ausgeführt wird. Wenn Sie versuchen, einen neuen Tab über windows.open innerhalb eines Versprechens, einer Zeitüberschreitung, eines Abonnements zu öffnen, ist der Browser der Ansicht, dass es sich um eine Manipulation des Benutzers handelt. Daher besteht die Lösung darin, vor dem Eingeben des Versprechens eine Instanz zu erstellen die href wie jonas
David
@ David Vielen Dank !!! Ich habe die .thenAntwort dann nicht gesehen und deshalb war ich so verwirrt: / SRY ...
Alejandro Vales
@ David Das ist großartig! Klappt wunderbar. Wenn ich Sie mit nur einer weiteren Frage belästigen könnte - wissen Sie, wie dies auch in Edge funktioniert? Ein Anstoß zu einer richtigen Ressource würde sehr helfen ...
Dzenesiz
21

Als gute Praxis halte ich es für eine gute Idee, zu testen, ob ein Popup blockiert wurde, und gegebenenfalls Maßnahmen zu ergreifen. Sie müssen wissen, dass window.open einen Rückgabewert hat. Dieser Wert kann null sein, wenn die Aktion fehlgeschlagen ist. Zum Beispiel im folgenden Code:

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

Wenn das Popup blockiert ist, gibt window.open null zurück. Die Funktion gibt also false zurück.

Stellen Sie sich als Beispiel vor, Sie rufen diese Funktion direkt von einem beliebigen Link mit auf target="_blank": Wenn das Popup erfolgreich geöffnet wurde, falseblockiert die Rückgabe die Verknüpfungsaktion. Wenn das Popup blockiert ist, truelässt die Rückgabe das Standardverhalten (neues _leeres Fenster öffnen) und fährt fort .

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

Auf diese Weise erhalten Sie ein Popup, wenn es funktioniert, und ein _blank-Fenster, wenn nicht.

Wenn das Popup nicht geöffnet wird, können Sie:

  • Öffnen Sie ein leeres Fenster wie im Beispiel und fahren Sie fort
  • öffne ein gefälschtes Popup (ein Iframe innerhalb der Seite)
  • Informieren Sie den Benutzer ("Bitte erlauben Sie Popups für diese Site")
  • Öffnen Sie ein leeres Fenster und informieren Sie den Benutzer usw.
FrancescoMM
quelle
Danke dir. Hat funktioniert!
Bcktr
8

von Googles oauth JavaScript API:

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

Sehen Sie den Bereich, in dem es liest:

Authentifizierung einrichten

Die Client-Implementierung von OAuth 2.0 verwendet ein Popup-Fenster, um den Benutzer aufzufordern, sich anzumelden und die Anwendung zu genehmigen. Der erste Aufruf von gapi.auth.authorize kann Popup-Blocker auslösen, da das Popup-Fenster indirekt geöffnet wird. Rufen Sie beim Laden des Clients gapi.auth.init (Rückruf) auf, um zu verhindern, dass der Popupblocker bei Authentifizierungsaufrufen ausgelöst wird. Der bereitgestellte Rückruf wird ausgeführt, wenn die Bibliothek bereit ist, Authentifizierungsaufrufe durchzuführen.

Ich würde vermuten, dass es sich auf die eigentliche Antwort oben bezieht, wie es erklärt, wenn es eine sofortige Antwort gibt, wird es den Popup-Alarm nicht auslösen. Die "gapi.auth.init" macht es so, dass die API sofort passiert.

Praktische Anwendung

Ich habe einen Open-Source-Authentifizierungsmikroservice mit dem Knotenpass auf npm und den verschiedenen Passpaketen für jeden Anbieter erstellt. Ich habe einen Standard-Redirect-Ansatz für den Drittanbieter verwendet und ihm eine Redirect-URL gegeben, zu der er zurückkehren kann. Dies war programmatisch, so dass ich verschiedene Orte haben konnte, an die ich zurückmelden konnte, wenn ich mich anmeldete / anmeldete und auf bestimmten Seiten.

github.com/sebringj/athu

passportjs.org

Jason Sebring
quelle
3

Ich habe mehrere Lösungen ausprobiert, aber seine ist die einzige, die in allen Browsern für mich funktioniert hat

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

pomobc
quelle
2
Dies funktioniert einfach nicht für Leute, die den Popup-Blocker aktiviert haben
Alejandro Vales
was ist url? es ist nicht zugeordnet.
Shinriyo
@shinriyo URL ist der Link zu jeder Seite, auf die Sie zugreifen möchten, zum Beispielhttp://example.com
Pomobc
@ AlejandroVales Ich habe Popup-Blocker aktiviert und es funktioniert. Das Problem ist, dass ein window.open()neues Fenster nicht programmgesteuert geöffnet werden kann. Wenn dies erforderlich ist, ist diese Antwort eine der Optionen. Mit der newTabVariablen, auf die wir verweisen, window.open()und später können wir sie aufrufen, die urlbenötigte URL einfügen , in meinem Fall die URL eines Blobs, und die neue Registerkarte wird mit der eingegebenen URL geöffnet.
Stanimirsp
0

Ich wollte die neue Seite erst erstellen, wenn der Rückruf erfolgreich zurückgegeben wurde. Daher habe ich dies getan, um den Benutzerklick zu simulieren :

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);
  });
}
user3479425
quelle
3
funktioniert bei mir in Chrome 62 nicht. Popup (Seite) wird blockiert.
s.ermakovich
1
Ja, Sie haben Recht - ich habe auch festgestellt, dass dies inkonsistent ist.
Am
-8

Der einfachste Weg, dies loszuwerden, ist:

  1. Verwenden Sie nicht document.open ().
  2. Verwenden Sie stattdessen this.document.location.href = location; Dabei ist Speicherort die zu ladende URL

Ex :

<script>
function loadUrl(location)
{
this.document.location.href = location;
}</script>

<div onclick="loadUrl('company_page.jsp')">Abc</div>

Das hat bei mir sehr gut funktioniert. Prost

Pramod Shetty
quelle
2
Was ist mit dem Öffnen einer URL in einem neuen Tab?
3 Regeln