Bắt lỗi nếu iframe src không tải được. Lỗi: - “Từ chối hiển thị 'http://www.google.co.in/' trong khung ..”


79

Tôi đang sử dụng Knockout.jsđể liên kết srcthẻ iframe (Thẻ này sẽ có thể định cấu hình đối với Người dùng).

Bây giờ, nếu người dùng đã định cấu hình http://www.google.com (tôi biết nó sẽ không tải trong iframe, đó là lý do tại sao tôi đang sử dụng nó cho kịch bản -ve) và điều đó phải được hiển thị trong IFrame. nhưng nó báo lỗi: -

Từ chối hiển thị ' http://www.google.co.in/ ' trong khung vì nó đặt 'X-Frame-Options' thành 'SAMEORIGIN'.

Tôi có mã sau cho Iframe: -

<iframe class="iframe" id="iframe" data-bind="attr: {src: externalAppUrl, height: iframeheight}">
    <p>Hi, This website does not supports IFrame</p>
</iframe>

Điều tôi muốn là, nếu URL không tải được. Tôi muốn hiển thị Thông báo tùy chỉnh . Ảnh chụp màn hình bảng điều khiển khi tôi gặp lỗi FIDDLE TẠI ĐÂY

Bây giờ, nếu tôi sử dụng onload và onerror như: -

<iframe id="browse" style="width:100%;height:100%" onload="alert('Done')" onerror="alert('Failed')"></iframe>

Nó hoạt động tốt khi tải w3schools.com nhưng không hoạt động với google.com.

Thứ hai: - nếu tôi tạo nó dưới dạng một hàm và thử như tôi đã làm trong trò chơi điện tử của mình, nó không hoạt động.

<iframe id="browse" style="width:100%;height:100%" onload="load" onerror="error"></iframe>

Tôi không biết tôi nên làm thế nào để nó chạy và bắt lỗi.

Đã chỉnh sửa: - Tôi đã thấy Muốn gọi một hàm nếu iframe không tải hoặc câu hỏi của tải trong stackoverflow nhưng nó hiển thị lỗi cho các trang web có thể được tải trong iframe.

Ngoài ra, tôi đã xem xét khung nội tuyến Stackoverflow khi tải sự kiện Cảm ơn !!

Câu trả lời:


44

Bạn sẽ không thể thực hiện việc này từ phía máy khách do Chính sách nguồn gốc giống nhau do trình duyệt đặt. Bạn sẽ không thể nhận được nhiều thông tin từ iFrame ngoài các thuộc tính cơ bản như chiều rộng và chiều cao của nó.

Ngoài ra, google đặt trong tiêu đề phản hồi của nó là ' X-Frame-Options ' của SAMEORIGIN.

Ngay cả khi bạn thực hiện một cuộc gọi ajax tới google, bạn sẽ không thể kiểm tra phản hồi vì trình duyệt thực thi Chính sách nguồn gốc giống nhau.

Vì vậy, tùy chọn duy nhất là thực hiện yêu cầu từ máy chủ của bạn để xem liệu bạn có thể hiển thị trang web trong IFrame của mình hay không.

Vì vậy, trên máy chủ của bạn .. ứng dụng web của bạn sẽ đưa ra yêu cầu đến www.google.com và sau đó kiểm tra phản hồi để xem phản hồi có đối số tiêu đề của X-Frame-Options hay không. Nếu nó tồn tại thì bạn biết IFrame sẽ lỗi.


Roblox sử dụng một iframethủ thuật để phát hiện xem trò chơi có được cài đặt hay không bằng <iframe src="roblox-player:foo">cách phát hiện trình xử lý URI tùy chỉnh. Việc phát hiện iframelỗi này sẽ kích hoạt nút "Tải xuống" xuất hiện. Làm thế nào để họ làm điều đó sau đó?
tresf

1
@QZ Hỗ trợ Tôi không biết bạn đang nói gì.
Evan Larsen

1
@EvanLarsen Tôi đang đề cập đến một trò chơi điện tử rất phổ biến sử dụng thành công <iframe>kỹ thuật này để khởi chạy (và tôi hy vọng có thể phát hiện) một trình xử lý URI đã đăng ký trong HĐH. Đó là một trò chơi miễn phí, bạn có thể cài đặt nó và tự xem. Khi bạn tham gia một trò chơi thông qua trình duyệt, nó sẽ sử dụng phương thức hack iframe để khởi chạy trò chơi. Nếu không thành công, họ sẽ hiển thị nút "tải xuống". Bằng cách nào đó họ biết liệu URI có được xử lý đúng cách hay không. Dự đoán ban đầu của tôi là bắt iframelỗi, nhưng các câu trả lời (cũng như các bài kiểm tra của tôi) dường như cho thấy rằng điều đó là không thể. Làm thế nào để họ biết khi iframe bị lỗi?
tresf

Đây chỉ là phỏng đoán nhưng tôi cá rằng trang web chỉ đang gọi một ứng dụng web tự lưu trữ trên máy cục bộ của bạn. Nếu cuộc gọi không thành công thì nó sẽ hiển thị nút tải xuống. Sau khi bạn tải xuống và cài đặt trò chơi trên máy của mình, trang web sẽ có thể gọi ứng dụng web tự lưu trữ cục bộ. Bởi ứng dụng web tự lưu trữ .. Ý tôi là chỉ một ứng dụng có điểm cuối http có thể được gọi bởi bất kỳ trang web nào biết về nó. (tức là. localhost: 7845 / opengame / room / 2534 )
Evan Larsen

Đây localhost:7845hoàn toàn là giả định. Đầu tiên, nó sẽ gặp phải cảnh báo / lỗi nội dung hỗn hợp (roblox.com sử dụng HTTPS) và tiếp theo, nó sẽ cần các cổng chuyển đổi dự phòng trong trường hợp xung đột. Kỹ thuật được sử dụng để khởi chạy phần mềm là một iframe. Điều này có thể được quan sát bằng cách kiểm tra nguồn trang. Bằng cách nào đó khi điều này không khởi chạy được phần mềm, họ có thể phát hiện ra nó. Điều này có thể được thực hiện thông qua phương pháp "điện thoại nhà riêng" + thời gian chờ bằng cách sử dụng ID trình theo dõi của trình duyệt. Tôi đề cập đến điều này bởi vì tính iframenăng phát hiện lỗi này rất hữu ích để khởi chạy các ứng dụng được liên kết, nhưng chỉ khi lỗi có thể được phát hiện.
tresf

15

Tôi nghĩ rằng bạn có thể liên kết loadsự kiện của iframe, sự kiện sẽ kích hoạt khi nội dung iframe được tải đầy đủ.

Đồng thời, bạn có thể bắt đầu setTimeout, nếu iFrame được tải, hãy xóa thời gian chờ hoặc để thời gian chờ kích hoạt.

Mã:

var iframeError;

function change() {
    var url = $("#addr").val();
    $("#browse").attr("src", url);
    iframeError = setTimeout(error, 5000);
}

function load(e) {
    alert(e);
}

function error() {
    alert('error');
}

$(document).ready(function () {
    $('#browse').on('load', (function () {
        load('ok');
        clearTimeout(iframeError);
    }));

});

Demo: http://jsfiddle.net/IrvinDominin/QXc6P/

Vấn đề thứ hai

Đó là bởi vì bạn bỏ lỡ các parens trong lệnh gọi hàm nội tuyến; hãy thử thay đổi điều này:

<iframe id="browse" style="width:100%;height:100%" onload="load" onerror="error"></iframe>

vào cái này:

<iframe id="browse" style="width:100%;height:100%" onload="load('Done func');" onerror="error('failed function');"></iframe>

Demo: http://jsfiddle.net/IrvinDominin/ALBXR/4/


51
Này, chỉ cần nhìn vào trò chơi - nó không bao giờ mắc lỗi.
vvohra87

12
Tôi đang trên Ubuntu và Chrome - không có vấn đề gì URL tôi đưa vào textbox nó nói "làm" và "done Func" :(
vvohra87

3
@IrvinDomininakaEdward: cả liên kết fiddle đều không hoạt động ... nó không mở ... bạn đã xóa fiddle chưa?
Hitesh

10
trừ 1 vì như nhận xét ở trên trạng thái: fiddle không bao giờ ném thông báo lỗi mong đợi khi iframe không tải được. điều này là do sự kiện tải của iframe kích hoạt ngay cả khi nó không tải nội dung.
CodeToad

3
Đây không phải là câu trả lời được chọn. Câu hỏi của Evan dưới đây là đúng: bảo mật của trình duyệt ngăn chặn việc phát hiện điều này.
Scott Smith

8

Onload sẽ luôn được kích hoạt, tôi giải quyết vấn đề này bằng cách sử dụng khối try catch. Nó sẽ đưa ra một ngoại lệ khi bạn cố lấy contentDocument.

iframe.onload = function(){
   var that = $(this)[0];
   try{
        that.contentDocument;
   }
   catch(err){
        //TODO 
   }
}

1
Đây là cách đơn giản nhất mà tôi đã thử cho đến nay và nó thực sự hoạt động!
Simon Jackson

15
Điều này cũng không làm việc cho các tên miền chéo - nó sẽ ném ra một lỗi trong hai cách
Luoruize

Điều này đã làm việc cho tôi, cho iframe của miền của riêng tôi. X-Frame-Options: SAMEORIGIN
Ryan

đối với tôi, nó ném ra cùng một ngoại lệ ngay cả khi iframe tải nội dung. làm thế nào để bạn biết nếu nội dung không được tải?
leeCoder

Tôi đã định trả lời rằng có thể mắc lỗi đó theo cách này! Nhưng bạn đã làm được! Tôi đang xử lý vấn đề chính xác tương tự (và cũng để kiểm tra xem người dùng có được chuyển hướng đến một trang nhất định trong miền của tôi hay không) theo cách này! Tôi đã gặp câu hỏi này khi tìm kiếm "xử lý lỗi trong iframe", nhưng hiện tôi đang gặp phải lỗi 503 bên trong iframe!
Sampgun

8

Đây là một sửa đổi nhỏ đối với câu trả lời của Edens - đối với tôi trong chrome không bắt được lỗi. Mặc dù bạn vẫn sẽ gặp lỗi trong bảng điều khiển: "Từ chối hiển thị ' https://www.google.ca/ ' trong một khung vì nó đặt 'X-Frame-Options' thành 'sameorigin'." Ít nhất điều này sẽ bắt được thông báo lỗi và sau đó bạn có thể xử lý nó.

 <iframe id="myframe" src="https://google.ca"></iframe>

 <script>
 myframe.onload = function(){
 var that = document.getElementById('myframe');

 try{
    (that.contentWindow||that.contentDocument).location.href;
 }
 catch(err){
    //err:SecurityError: Blocked a frame with origin "http://*********" from accessing a cross-origin frame.
    console.log('err:'+err);
}
}
</script>

Điều này dẫn đến lỗi "không thể đọc thuộc tính 'vị trí' của null" that.contentDocumentvà nhiều trang web đang hoạt động sẽ vẫn gặp lỗi that.contentWindowtrong quá trình tải.
Giỏ hàng bị bỏ rơi

1

Tôi phải đối mặt với vấn đề tương tự. Tôi đã giải quyết nó mà không sử dụng trình xử lý onload. Tôi đang làm việc trong dự án AngularJs nên tôi đã sử dụng $ khoảng thời gian và $ thời gian chờ. Bạn cũng có thể sử dụng setTimeout và setInterval. Đây là mã:

 var stopPolling;
 var doIframePolling;
 $scope.showIframe = true;
 doIframePolling = $interval(function () {
    if(document.getElementById('UrlIframe') && document.getElementById('UrlIframe').contentDocument.head && document.getElementById('UrlIframe').contentDocument.head.innerHTML != ''){
        $interval.cancel(doIframePolling);
        doIframePolling = undefined;
        $timeout.cancel(stopPolling);
        stopPolling = undefined;
        $scope.showIframe = true;
    }
},400);

stopPolling = $timeout(function () {
        $interval.cancel(doIframePolling);
        doIframePolling = undefined;
        $timeout.cancel(stopPolling);
        stopPolling = undefined;
        $scope.showIframe = false;     
},5000);

 $scope.$on("$destroy",function() {
        $timeout.cancel(stopPolling);
        $interval.cancel(doIframePolling);
 });

Cứ sau 0,4 giây, hãy tiếp tục kiểm tra phần đầu của Tài liệu iFrame. I somthing is present.Loading không bị CORS dừng vì lỗi CORS hiển thị trang trống. Nếu không có gì xuất hiện sau 5 giây, có một số lỗi (chính sách Cors), v.v. Hiển thị thông báo phù hợp. Cảm ơn. Tôi hy vọng nó giải quyết được vấn đề của bạn.


2
Uncaught DOMException: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': Blocked a frame with origin "..." from accessing a cross-origin frame.- bạn có chắc nó đang hoạt động trên nhiều miền không?
Mars Robertson

0

Tôi gặp vấn đề tương tự, chrome không thể kích hoạt lỗi khi tải iframe src.

nhưng trong trường hợp của tôi, tôi chỉ cần thực hiện một yêu cầu http tên miền chéo, vì vậy tôi sử dụng script src / onload / onerror thay vì iframe. nó hoạt động tốt.


0

Tôi đã giải quyết nó với window.length. Nhưng với giải pháp này, bạn có thể nhận được lỗi hiện tại (X-Frame hoặc 404).

iframe.onload = event => {
   const isLoaded = event.target.contentWindow.window.length // 0 or 1
}

MSDN


0

Như đã giải thích trong câu trả lời được chấp nhận, https://stackoverflow.com/a/18665488/4038790 , bạn cần kiểm tra qua máy chủ.

Vì không có cách nào đáng tin cậy để kiểm tra điều này trong trình duyệt, tôi khuyên bạn nên xây dựng cho mình một điểm cuối máy chủ nhanh mà bạn có thể sử dụng để kiểm tra xem có url nào có thể tải được qua iframe hay không. Khi máy chủ của bạn đã khởi động và đang chạy, chỉ cần gửi yêu cầu AJAX tới nó để kiểm tra bất kỳ url nào bằng cách cung cấp url trong chuỗi truy vấn dưới dạng url(hoặc bất kỳ thứ gì máy chủ của bạn mong muốn). Đây là mã máy chủ trong NodeJs:

const express = require('express')
const app = express()

app.get('/checkCanLoadIframeUrl', (req, res) => {
  const request = require('request')
  const Q = require('q')

  return Q.Promise((resolve) => {
    const url = decodeURIComponent(req.query.url)

    const deafultTimeout = setTimeout(() => {
      // Default to false if no response after 10 seconds
      resolve(false)
    }, 10000)

    request({
        url,
        jar: true /** Maintain cookies through redirects */
      })
      .on('response', (remoteRes) => {
        const opts = (remoteRes.headers['x-frame-options'] || '').toLowerCase()
        resolve(!opts || (opts !== 'deny' && opts !== 'sameorigin'))
        clearTimeout(deafultTimeout)
      })
      .on('error', function() {
        resolve(false)
        clearTimeout(deafultTimeout)
      })
  }).then((result) => {
    return res.status(200).json(!!result)
  })
})

app.listen(process.env.PORT || 3100)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.