ฉันกำลังเขียนแอพ Facebook ที่ใช้ iframe ตอนนี้ฉันต้องการใช้หน้า html เดียวกันเพื่อแสดงผลเว็บไซต์ปกติเช่นเดียวกับเพจ Canvas ภายใน Facebook ฉันต้องการทราบว่าฉันสามารถตรวจสอบว่าหน้าได้รับการโหลดภายใน iframe หรือโดยตรงในเบราว์เซอร์?
ฉันกำลังเขียนแอพ Facebook ที่ใช้ iframe ตอนนี้ฉันต้องการใช้หน้า html เดียวกันเพื่อแสดงผลเว็บไซต์ปกติเช่นเดียวกับเพจ Canvas ภายใน Facebook ฉันต้องการทราบว่าฉันสามารถตรวจสอบว่าหน้าได้รับการโหลดภายใน iframe หรือโดยตรงในเบราว์เซอร์?
คำตอบ:
เบราว์เซอร์สามารถปิดกั้นการเข้าถึงwindow.top
เนื่องจากนโยบายกำเนิดเดียวกัน ข้อบกพร่องของ IE ก็เกิดขึ้นเช่นกัน นี่คือรหัสการทำงาน:
function inIframe () {
try {
return window.self !== window.top;
} catch (e) {
return true;
}
}
top
และself
เป็นทั้งwindow
วัตถุ (พร้อมด้วยparent
) ดังนั้นคุณจะเห็นว่าหน้าต่างของคุณเป็นหน้าต่างด้านบนหรือไม่
window.self !== window.top
ผลตอบแทนtrue
เมื่อเรียกใช้จากภายในเนื้อหาของframe
, หรือ iframe
เมื่ออยู่ใน iframe บนต้นกำเนิดเดียวกันกับพาเรนต์window.frameElement
เมธอดจะส่งคืนองค์ประกอบ (เช่นiframe
หรือobject
) ที่ฝังหน้าต่าง null
มิฉะนั้นถ้าการเรียกดูในบริบทระดับบนหรือถ้าผู้ปกครองและกรอบเด็กที่มีต้นกำเนิดที่แตกต่างกันก็จะประเมิน
window.frameElement
? 'embedded in iframe or object'
: 'not embedded or cross-origin'
นี่คือมาตรฐาน HTMLพร้อมการสนับสนุนขั้นพื้นฐานในเบราว์เซอร์ที่ทันสมัยทั้งหมด
null
เข้าและออกจากiframe
Returns the element (such as <iframe> or <object>) in which the window is embedded, or null if the element is either top-level or is embedded into a document with a different script origin; that is, in cross-origin situations.
RoBorg ถูกต้อง แต่ฉันต้องการที่จะเพิ่มบันทึกด้านข้าง
ใน IE7 / IE8 เมื่อ Microsoft เพิ่มแท็บลงในเบราว์เซอร์พวกเขาทำสิ่งหนึ่งที่จะทำให้เกิดความเสียหายกับ JS ของคุณหากคุณไม่ระวัง
ลองนึกภาพเค้าโครงหน้านี้:
MainPage.html
IframedPage1.html (named "foo")
IframedPage2.html (named "bar")
IframedPage3.html (named "baz")
ตอนนี้ในเฟรม "baz" คุณคลิกลิงก์ (ไม่มีเป้าหมายโหลดในเฟรม "baz") มันใช้งานได้ดี
หากหน้าเว็บที่ได้รับการโหลดให้เรียกมันว่า special.html ใช้ JS เพื่อตรวจสอบว่า "มัน" มีเฟรมหลักชื่อ "บาร์" หรือไม่มันจะกลับมาจริง (คาดว่า)
ตอนนี้ให้บอกว่าหน้าพิเศษ.htmlเมื่อมันโหลดตรวจสอบเฟรมหลัก (สำหรับการมีอยู่และชื่อและถ้าเป็น "บาร์" มันจะโหลดตัวเองในเฟรมบาร์เช่น
if(window.parent && window.parent.name == 'bar'){
window.parent.location = self.location;
}
จนถึงตอนนี้ดีมาก ตอนนี้ข้อผิดพลาดมา
ให้บอกว่าแทนที่จะคลิกที่ลิงค์เดิมเช่นปกติและโหลดหน้าพิเศษ.htmlในกรอบ "baz" คุณคลิกกลางหรือเลือกที่จะเปิดในแท็บใหม่
เมื่อแท็บใหม่นั้นโหลด ( โดยไม่มีเฟรมหลักเลย! ) IE จะเข้าสู่วงวนไม่รู้จบของการโหลดหน้าเว็บ! เนื่องจาก IE "คัดลอก" โครงสร้างของเฟรมใน JavaScript ดังนั้นแท็บใหม่จะมีพาเรนต์และพาเรนต์นั้นมีชื่อ "bar"
ข่าวดีก็คือการตรวจสอบ:
if(self == top){
//this returns true!
}
ในแท็บใหม่นั้นคืนค่าจริงและทำให้คุณสามารถทดสอบเงื่อนไขแปลก ๆ นี้ได้
window.parent
เสมอ
คำตอบที่ยอมรับไม่ได้สำหรับฉันภายในสคริปต์เนื้อหาของ Firefox 6.0 Extension (Addon-SDK 1.0): Firefox ดำเนินการสคริปต์เนื้อหาในแต่ละ: หน้าต่างระดับบนสุดและใน iframes ทั้งหมด
ภายในสคริปต์เนื้อหาฉันได้รับผลลัพธ์ต่อไปนี้:
(window !== window.top) : false
(window.self !== window.top) : true
สิ่งที่แปลกเกี่ยวกับผลลัพธ์นี้ก็คือมันจะเหมือนเดิมเสมอไม่ว่าจะรันโค้ดใน iframe หรือหน้าต่างระดับบนสุดก็ตาม
ในทางกลับกัน Google Chrome ดูเหมือนว่าจะรันสคริปต์เนื้อหาของฉันเพียงครั้งเดียวภายในหน้าต่างระดับบนสุดดังนั้นสิ่งที่กล่าวมาจะไม่ทำงานเลย
สิ่งที่ได้ผลสำหรับฉันในสคริปต์เนื้อหาในเบราว์เซอร์ทั้งสองคือ:
console.log(window.frames.length + ':' + parent.frames.length);
โดยไม่ต้องพิมพ์ใน iframe นี้0:0
ในหน้าต่างระดับบนสุดที่มีกรอบมันพิมพ์1:1
และใน iframe 0:1
เพียงของเอกสารมันพิมพ์
สิ่งนี้ทำให้ส่วนขยายของฉันสามารถระบุได้ทั้งในเบราว์เซอร์หากมี iframes ใด ๆ อยู่และนอกจากนี้ใน Firefox หากมีการเรียกใช้ภายใน iframes ใดตัวหนึ่ง
document.defaultView.self === document.defaultView.top
window !== window.top
ในสคริปต์เนื้อหา add-on SDK ของ Firefox self
วัตถุทั่วโลกเป็นวัตถุที่ใช้ในการสื่อสารกับสคริปต์หลัก
ฉันไม่แน่ใจว่าตัวอย่างนี้ใช้ได้กับเว็บเบราว์เซอร์รุ่นเก่า แต่ฉันใช้สิ่งนี้กับ IE, Firefox และ Chrome ที่ไม่มีและปัญหา:
var iFrameDetection = (window === window.parent) ? false : true;
!(window===window.parent)
ฉันใช้สิ่งนี้:
var isIframe = (self.frameElement && (self.frameElement+"").indexOf("HTMLIFrameElement") > -1);
.indexOf("HTMLIFrameElement")
?
ใช้ฟังก์ชั่นจาวาสคริปต์นี้เป็นตัวอย่างในการทำสิ่งนี้ให้สำเร็จ
function isNoIframeOrIframeInMyHost() {
// Validation: it must be loaded as the top page, or if it is loaded in an iframe
// then it must be embedded in my own domain.
// Info: IF top.location.href is not accessible THEN it is embedded in an iframe
// and the domains are different.
var myresult = true;
try {
var tophref = top.location.href;
var tophostname = top.location.hostname.toString();
var myhref = location.href;
if (tophref === myhref) {
myresult = true;
} else if (tophostname !== "www.yourdomain.com") {
myresult = false;
}
} catch (error) {
// error is a permission error that top.location.href is not accessible
// (which means parent domain <> iframe domain)!
myresult = false;
}
return myresult;
}
โซลูชันอื่นไม่ทำงานสำหรับฉัน อันนี้ใช้ได้กับเบราว์เซอร์ทั้งหมด:
วิธีหนึ่งในการป้องกันการคลิกแจ็คกิ้งคือการรวมสคริปต์ "ตัวทำลายเฟรม" ไว้ในแต่ละหน้าเว็บที่ไม่ควรทำกรอบ วิธีการต่อไปนี้จะป้องกันเว็บเพจจากการถูกวางกรอบแม้ในเบราว์เซอร์ดั้งเดิมที่ไม่สนับสนุน X-Frame-Options-Header
ในองค์ประกอบ HEAD ของเอกสารให้เพิ่มสิ่งต่อไปนี้:
<style id="antiClickjack">body{display:none !important;}</style>
ก่อนอื่นให้ใช้ ID กับองค์ประกอบสไตล์เอง:
<script type="text/javascript">
if (self === top) {
var antiClickjack = document.getElementById("antiClickjack");
antiClickjack.parentNode.removeChild(antiClickjack);
} else {
top.location = self.location;
}
</script>
ด้วยวิธีนี้ทุกอย่างสามารถอยู่ในส่วนหัวของเอกสารและคุณต้องการเพียงหนึ่งวิธี / taglib ใน API ของคุณ
การอ้างอิง: https://www.codemagi.com/blog/post/194
if ( window.location !== window.parent.location )
{
// The page is in an iframe
}
else
{
// The page is not in an iframe
}
เนื่องจากคุณถูกถามในบริบทของแอพ facebook คุณอาจต้องการพิจารณาตรวจจับสิ่งนี้ที่เซิร์ฟเวอร์เมื่อมีการร้องขอครั้งแรก Facebook จะส่งข้อมูลการสอบถามจำนวนมากรวมถึงคีย์ fb_sig_user หากมีการเรียกใช้จาก iframe
เนื่องจากคุณอาจต้องตรวจสอบและใช้ข้อมูลนี้ในแอปของคุณอยู่ให้ใช้เพื่อกำหนดบริบทที่เหมาะสมในการแสดงผล
จริง ๆ แล้วฉันเคยตรวจสอบ window.parent และมันใช้งานได้สำหรับฉัน แต่เมื่อเร็ว ๆ นี้ window เป็นวัตถุแบบวงกลมและมักจะมีคีย์หลัก iframe หรือ iframe
เป็นความคิดเห็นที่แนะนำให้เปรียบเทียบอย่างหนักกับ window.parent ทำงาน ไม่แน่ใจว่าจะใช้งานได้หรือไม่หาก iframe นั้นเป็นหน้าเว็บเดียวกับพ่อแม่
window === window.parent;
window.parent === window
เป็นจริง ดังนั้นคำตอบของคุณไม่ถูกต้อง และการรวบรวมนี้สามารถใช้ตรวจสอบได้ (อย่างน้อยก็ใน Chrome ไม่ได้ทดสอบในเบราว์เซอร์อื่น)
มันเป็นโค้ดโบราณที่ฉันใช้ไปสองสามครั้ง:
if (parent.location.href == self.location.href) {
window.location.href = 'https://www.facebook.com/pagename?v=app_1357902468';
}
(parent.location == self.location)
parent.location
ได้ มิฉะนั้นจะมีการโยนข้อยกเว้น
หากคุณต้องการทราบว่าผู้ใช้เข้าถึงแอพของคุณจากแท็บหน้า Facebook หรือผ้าใบตรวจสอบคำขอลงนาม หากคุณไม่ได้รับอาจเป็นผู้ใช้ที่ไม่ได้เข้าถึงจาก facebook เพื่อให้แน่ใจว่าได้ยืนยันโครงสร้างเขตข้อมูล Sign_request และเนื้อหาในฟิลด์
ด้วย php-sdk คุณจะได้รับคำขอที่ลงนามเช่นนี้:
$signed_request = $facebook->getSignedRequest();
คุณสามารถอ่านเพิ่มเติมเกี่ยวกับคำขอลงนามได้ที่นี่:
https://developers.facebook.com/docs/reference/php/facebook-getSignedRequest/
และที่นี่:
https://developers.facebook.com/docs/reference/login/signed-request/
นี่เป็นวิธีแก้ปัญหาที่ง่ายที่สุดสำหรับฉัน
<p id="demofsdfsdfs"></p>
<script>
if(window.self !== window.top) {
//run this code if in an iframe
document.getElementById("demofsdfsdfs").innerHTML = "in frame";
}else{
//run code if not in an iframe
document.getElementById("demofsdfsdfs").innerHTML = "no frame";
}
</script>
if (window.frames.length != parent.frames.length) { page loaded in iframe }
แต่ถ้า iframe มีจำนวนแตกต่างกันในหน้าและหน้าของคุณที่โหลดคุณใน iframe ทำให้ iframe ในหน้าของคุณไม่มีการรับประกัน 100% สำหรับผลลัพธ์ของรหัสนี้
เขียนจาวาสคริปต์นี้ในแต่ละหน้า
if (self == top)
{ window.location = "Home.aspx"; }
จากนั้นจะเปลี่ยนเส้นทางไปยังหน้าแรกโดยอัตโนมัติ