หลีกเลี่ยงตัวบล็อกป๊อปอัปของเบราว์เซอร์


172

ฉันกำลังพัฒนาโฟลว์การพิสูจน์ตัวตน OAuth อย่างหมดจดใน JavaScript และฉันต้องการให้ผู้ใช้เห็นหน้าต่าง "ให้สิทธิ์การเข้าถึง" ในป๊อปอัป แต่ถูกบล็อก

ฉันจะป้องกันหน้าต่างป็อปอัพที่สร้างขึ้นโดยwindow.openหรือwindow.showModalDialogถูกบล็อคโดยตัวบล็อกป็อปอัพของเบราว์เซอร์ที่ต่างกันได้อย่างไร


11
แม้ว่ามันจะเป็นไปได้ (ฉันไม่รู้) ถ้าคนใช้ตัวบล็อกป๊อปอัพคุณควรเคารพมัน เบราว์เซอร์ส่วนใหญ่แสดงข้อความเมื่อไซต์พยายามเปิดป๊อปอัพเพื่อให้พวกเขายังคงสามารถดูได้หากพวกเขาต้องการ คุณสามารถใส่ข้อสังเกตในเว็บไซต์ของคุณว่าเนื้อหาบางอย่างเปิดขึ้นในป๊อปอัพและผู้ใช้ควรอนุญาตให้ดำเนินการต่อไป
เฟลิกซ์คลิง

5
วิธีปฏิบัติที่ดีที่สุดจะมีลักษณะดังนี้: 1) ทำสิ่งนี้ให้สำเร็จ 2) ปิดหน้าต่างและกั้นประตูของคุณและยืนตระหง่านด้วยความกลัวจากการรวมตัวกันของผู้อุปถัมภ์เว็บที่อารมณ์เสีย 3) กลับใจเอาป๊อปอัพบัสตา ผู้ชมของคุณ
Alex Mcp

อเล็กซ์และเฟลิกซ์ฉันได้อัปเดตคำถามแล้ว ฉันจะไม่ใช้ความรู้กับสิ่งชั่วร้าย :) ขอบคุณ!
Pablo Fernandez

9
ฉันต้องการเพิ่มที่ผ่านตัวบล็อกป๊อปอัพอาจพยายามทำให้ประสบการณ์ผู้ใช้ดีขึ้น ในตัวอย่างที่ฉันกำลังดำเนินการตอนนี้เรากำลังใช้แอปพลิเคชัน Javascript (ขึ้นอยู่กับ ExtJS) และเราพยายามให้ผู้ใช้ชำระเงินด้วย paypal เราให้ปุ่มแก่พวกเขาพวกเขาสามารถคลิกเพื่อเปิด paypal ในหน้าต่างใหม่ได้ แต่ IE บางรุ่นกำลังปิดกั้นมันในฐานะป๊อปอัพ (แม้ว่าจะเป็นการคลิกปุ่ม) หากพวกเขาเปิดใช้งานป๊อปอัพหน้าจอจะโหลดซ้ำและเป็นแอป JavaScript เราจะสูญเสียสถานะหน้าต่างและพวกเขาจะต้องเริ่มต้นใหม่ ดังนั้นจริงๆ: ปัญหาคือ IE เป็นใบ้
NateDSaint

1
@ FelixKling ใช่มันเป็นไปได้ ผู้ผลิตเบราว์เซอร์คิดเรื่องนี้แล้ว การเปิดป๊อปอัพนั้นถือว่าใช้ได้ตราบใดที่มีเจตนาของผู้ใช้ (ให้สัญญาณโดยผู้ใช้คลิกที่ลิงค์หรือปุ่ม) ตัวบล็อกป๊อปอัปควรเคารพเจตนาของผู้ใช้ หากตัวป้องกันป๊อปอัปของ IE ไม่เช่นนั้นจะเป็นตัวป้องกันป๊อปอัปที่ผิด ผู้ใช้ใช้ตัวบล็อกป๊อปอัพเพื่อป้องกันสคริปต์จากการเปิดป๊อปอัปตามความประสงค์ไม่ใช่เพื่อปิดกั้นป๊อปอัปที่พวกเขาพยายามเปิด (โดยการคลิกปุ่มหรือลิงก์)
Stijn de Witt

คำตอบ:


286

กฎทั่วไปคือว่าอัพป๊อปอัพจะมีส่วนร่วมหากwindow.openหรือคล้ายกันถูกเรียกจากจาวาสคริปต์ที่ไม่ได้เรียกโดยกระทำของผู้ใช้โดยตรง นั่นคือคุณสามารถwindow.openตอบสนองต่อการคลิกปุ่มโดยไม่ได้รับผลกระทบจากตัวป้องกันป๊อปอัป แต่ถ้าคุณใส่รหัสเดียวกันในเหตุการณ์ตัวจับเวลามันจะถูกบล็อก ความลึกของสายโซ่ก็เป็นอีกปัจจัยหนึ่ง - เบราว์เซอร์รุ่นเก่าบางรุ่นจะมองเฉพาะผู้โทรทันทีเบราว์เซอร์ที่ใหม่กว่าสามารถย้อนรอยเล็กน้อยเพื่อดูว่าผู้โทรโทรมานั้นเป็นการคลิกเมาส์เป็นต้นหรือไม่


2
น่าสนใจป๊อปอัปที่เริ่มต้นจากเหตุการณ์การเปลี่ยนแปลงที่เชื่อมโยงกับองค์ประกอบที่เลือกจะถูกบล็อก (ใน Chrome ไม่ใช่ FF) แม้ว่าเหตุการณ์นั้นจะเริ่มต้นโดยการกระทำของผู้ใช้โดยตรงเช่นการคลิก แม้ว่าจะถูกผูกไว้กับอินพุต แต่ก็อนุญาต แปลก.
ccnokes

6
ไม่มีใครพูดว่าเบราว์เซอร์สอดคล้องกัน : P
dthorpe

8
จากการทดลองฉันต้องเข้าใจว่าความลึกของกองซ้อนไม่เกี่ยวข้องกับตัวป้องกันป๊อปอัป มันจะตรวจสอบว่า window.open ถูกเรียกว่าภายใน 1 วินาทีหลังจากการกระทำของผู้ใช้หรือไม่ ทดสอบใน Chrome 46 และ Firefox 42
Mesqalito

1 หมดเวลาสองสามารถโกงในเบราว์เซอร์ทั้งเพื่อให้สามารถไม่มีกำหนดระยะเวลาการใช้คำตอบโดย @ TJ-Crowder ในหน้านี้ .. มี URL ที่คุณกำลังเรียกผ่านทางอาแจ็กซ์เป็น PHP บางคน (หรืออะไรก็ตาม) ที่ใช้การนอนหลับ ( ) สำหรับระยะเวลาก่อนที่จะส่งคืนการตอบสนอง เบราว์เซอร์จะค้างในขณะที่ 'โหลด' หน้า .. จากนั้นเรียกป๊อปอัปเมื่อได้รับการตอบกลับ อย่างไรก็ตามใน Chrome คุณต้องเพิ่มการแจ้งเตือน () ข้างหน้า ajax () เพื่อให้การหลอกลวงนี้ใช้งานได้
การประโคม

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 's
Swiss Mister

5
Whatever it is you intend to do, there is a better way than a popup windowฮ่า ๆ? ลักษณะทั่วไปที่แปลก ลูกค้าต้องการหน้าเว็บที่พวกเขารับรองความถูกต้องที่จะยังคงเปิดอยู่และหน้าเว็บไซต์ / หน้า Landing Page ใหม่หลังจากการตรวจสอบสิทธิ์เพื่อเปิดในแท็บใหม่ ใช่ไม่ใช่ความคิดของฉันเกี่ยวกับประสบการณ์การใช้งานที่ยอดเยี่ยม ... แต่ดูเหมือนสมเหตุสมผล
Don Cheadle

@mmcrae นั่งลงและคิดอย่างจริงจัง ฉันสัญญาว่าคุณจะพบ "การกระทำของผู้ใช้" ในสถานการณ์ที่คุณอธิบาย ประเด็นทั้งหมดของคำตอบของฉันคือคุณสร้างหน้าต่างป๊อปอัพเมื่อคุณมีการกระทำของผู้ใช้ - จากนั้นเติมด้วยเนื้อหาในภายหลัง คำแนะนำสำหรับกรณีของคุณ: ผู้ใช้เยี่ยมชม "รับรองความถูกต้อง" -> สร้างป๊อปอัพ (ว่าง); ตัวจับเวลาขึ้นหรือตอบกลับจากเซิร์ฟเวอร์หรืออะไรก็ตาม -> เติมเนื้อหาลงในป๊อปอัพ
Swiss Mister

3
เคล็ดลับที่เป็นประโยชน์หากคำขอ ajax ล้มเหลวให้โทรimportantStuff.closeเพื่อปิดแท็บใหม่และแจ้งเตือนและให้บริการในหน้าต้นฉบับ
Goose

24

นอกจากโพสต์มิสเตอร์สวิสในกรณีของฉันwindow.openเปิดตัวในสัญญาซึ่งเปิดตัวป้องกันป๊อปอัพทางออกของฉันคือ: ในเชิงมุม:

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

นี่คือวิธีที่คุณสามารถเปิดแท็บใหม่โดยใช้การตอบรับสัญญาและไม่เรียกใช้ตัวบล็อกป๊อปอัป


1
นี่นำไปสู่ทางออกของฉัน! ที่ฉันสร้างตัวแปรที่มีแท็บที่เปิดอยู่จากนั้นเติม URL หลังจากที่โหลดข้อมูลแล้ว ขอบคุณ const tab = window.open(); observable.subscribe(dataUrl => tab.location.href = dataUrl);
Jonas

1
หากคุณเปิดใช้งานตัวป้องกันป๊อปอัปสิ่งนี้จะไม่แก้ไขปัญหาด้วยตัวบล็อกป็อปอัพ ...
Alejandro Vales

@Alejandro Vales โซลูชัน jonas จะทำงานเฉพาะในกรณีที่รหัสจะเรียกใช้จากเหตุการณ์ onClick หรือการโต้ตอบกับผู้ใช้ เมื่อคุณพยายามที่จะเปิดแท็บใหม่ผ่าน windows.open ภายในสัญญาหมดเวลาสมัครสมาชิก ... เบราว์เซอร์คิดว่ามันเป็นการจัดการกับผู้ใช้ดังนั้นการแก้ปัญหาคือการสร้างตัวอย่างก่อนที่จะเข้าสู่สัญญาภายในคุณเพียงแค่เปลี่ยน href เหมือนโจนัสทำ
เดวิด

@ David ขอบคุณมาก !!! ฉันไม่ได้เห็น.thenคำตอบในตอนนั้นและนั่นคือสาเหตุที่ฉันสับสน: / SRY ...
Alejandro Vales

@ David นี่มันเยี่ยมมาก! ทำงานเหมือนจับใจ ถ้าฉันรบกวนคุณด้วยคำถามอีกหนึ่งคำถามคุณรู้วิธีทำให้งานนี้เป็น Edge ด้วยหรือไม่ การเขยิบทรัพยากรที่ถูกต้องจะช่วยได้มาก ...
dzenesiz

21

ตามแนวทางปฏิบัติที่ดีฉันคิดว่าควรทดสอบว่าป๊อปอัปถูกบล็อกและดำเนินการในกรณีหรือไม่ คุณต้องรู้ว่า 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;
}

หากป๊อปอัปถูกบล็อก window.open จะคืนค่าว่าง ดังนั้นฟังก์ชันจะคืนค่าเท็จ

ลองจินตนาการถึงการเรียกฟังก์ชั่นนี้โดยตรงจากลิงก์ใด ๆ ที่มีtarget="_blank": หากป๊อปอัพเปิดสำเร็จการกลับมา falseจะบล็อกการทำงานของลิงก์มิฉะนั้นถ้าป๊อปอัปถูกบล็อกการกลับมาtrueจะทำให้พฤติกรรมเริ่มต้น (เปิดหน้าต่าง _blank ใหม่) .

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

วิธีนี้คุณจะมีป๊อปอัปหากใช้งานได้และมีหน้าต่าง _blank หากไม่มี

หากป๊อปอัปไม่เปิดขึ้นคุณสามารถ:

  • เปิดหน้าต่างว่างเหมือนในตัวอย่างและดำเนินการต่อ
  • เปิดป๊อปอัปปลอม (iframe ภายในหน้า)
  • แจ้งผู้ใช้ ("โปรดอนุญาตป๊อปอัปสำหรับไซต์นี้")
  • เปิดหน้าต่างว่างแล้วแจ้งผู้ใช้ ฯลฯ

ขอบคุณ. ทำงาน!
Bcktr

8

จาก API JavaScript oauth ของ Google:

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 เกิดขึ้นทันที

การใช้งานจริง

ฉันสร้าง microservice การรับรองความถูกต้องโอเพนซอร์ซโดยใช้โหนดพาสปอร์ตบนน. น. และแพคเกจหนังสือเดินทางต่าง ๆ สำหรับแต่ละผู้ให้บริการ ฉันใช้วิธีการเปลี่ยนเส้นทางแบบมาตรฐานไปยังบุคคลที่สามโดยให้ URL การเปลี่ยนเส้นทางกลับมา นี่คือการเขียนโปรแกรมดังนั้นฉันสามารถมีสถานที่ที่แตกต่างกันเพื่อเปลี่ยนเส้นทางกลับไปถ้าเข้าสู่ระบบ / สมัครสมาชิกและในบางหน้า

github.com/sebringj/athu

passportjs.org


3

ฉันลองใช้วิธีแก้ไขปัญหาต่าง ๆ แต่เขาเป็นคนเดียวที่ใช้งานได้จริงสำหรับฉันในเบราว์เซอร์ทั้งหมด

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


2
สิ่งนี้ใช้ไม่ได้กับคนที่เปิดใช้งานตัวป้องกันป๊อปอัป
Alejandro Vales

คือurlอะไร มันไม่ได้รับมอบหมาย
24921

@shinriyo url คือลิงค์ไปยังหน้าอะไรก็ตามที่คุณต้องการเข้าใช้http://example.com
pomobc

@AlejandroVales ฉันเปิดใช้งานตัวป้องกันป๊อปอัปและทำงานได้ ปัญหาคือwindow.open()ไม่สามารถเปิดหน้าต่างใหม่โดยทางโปรแกรมและถ้าเราต้องการคำตอบนั้นเป็นหนึ่งในตัวเลือก ด้วยnewTabตัวแปรที่เราอ้างอิงถึงwindow.open()และหลังจากนั้นเราสามารถเรียกมันใส่สิ่งที่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

1
ใช่คุณพูดถูก - ฉันพบว่าเรื่องนี้ไม่สอดคล้องกัน ฉันลงเอยด้วยการเรียก API ของฉันแบบซิงโครนัส
user3479425

-8

วิธีที่ง่ายที่สุดในการกำจัดสิ่งนี้คือ:

  1. อย่าใช้ document.open ()
  2. ใช้ this.document.location.href = location แทน โดยที่ 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.