loadイベントを使用して、iframeのコンテンツがロードされたことを検出できます。残念ながら、私の目的のために、これには2つの問題があります。
上記のエラーのいずれかが発生したかどうかを確実に判断できる方法はありますか?
私はMozilla/XULRunnerに基づいたセミウェブセミデスクトップアプリケーションを書いているので、Mozillaでのみ機能するソリューションを歓迎します。
Iframeページを制御できる場合(およびページが同じドメイン名にある場合)、戦略は次のようになります。
var iFrameLoaded = false;
を初期化しますtrue
に設定し、iframeドキュメントから親の関数(setIFrameLoaded();
などを呼び出します。iFrameLoaded
オブジェクトを使用してtimer
フラグを確認します(タイマーをお好みのタイムアウト制限に設定します)-フラグがまだfalseの場合、iframeが定期的にロードされていないことがわかります。これが役立つことを願っています。
最近この問題が発生し、親ページ(IFRAMEタグを含む)でJavaScriptポーリングアクションを設定することに頼らなければなりませんでした。このJavaScript関数は、IFRAMEのコンテンツをチェックして、GOOD応答にのみ存在する明示的な要素を探します。もちろん、これは「同じオリジンポリシー」に違反することに対処する必要がないことを前提としています。
多くの異なるネットワークリソースから生成される可能性のあるすべてのエラーをチェックする代わりに、応答が良好であることがわかっている1つの一定の肯定的な要素をチェックしました。
所定の時間および/または予想される要素の検出に失敗した回数の後に、JavaScriptはIFRAMEのSRC属性を変更します(私のサーブレットからリクエストするため)、一般的なHTTPエラーメッセージを表示するのではなく、ユーザーフレンドリーなエラーページ。 JavaScriptは、SRC属性を簡単に変更して、まったく異なる要求を行うこともできます。
function checkForContents(){
var contents=document.getElementById('myiframe').contentWindow.document
if(contents){
alert('found contents of myiframe:' + contents);
if(contents.documentElement){
if(contents.documentElement.innerHTML){
alert("Found contents: " +contents.documentElement.innerHTML);
if(contents.documentElement.innerHTML.indexOf("FIND_ME") > -1){
openMediumWindow("woot.html", "mypopup");
}
}
}
}
}
これは非常に遅い答えですが、必要な人に任せます。
タスク:iframeクロスオリジンコンテンツをロードし、成功時にonLoaded
を発行し、ロードエラー時にonError
を発行します。
これは、私が開発できる最もクロスブラウザなOrigin独立ソリューションです。しかし、まず最初に、私が持っていた他のアプローチとそれらが悪い理由について簡単に説明します。
1。iframe iframeにはonload
イベントしかなく、ロード時およびエラー時に呼び出され、エラーであるかどうかを知る方法はありません。
2。performance.getEntriesByType( 'resource')。このメソッドは、ロードされたリソースを返します。必要なもののように聞こえます。しかし、残念なことに、firefoxは、リソースが読み込まれても失敗しても、常にリソース配列にリソースを追加します。 Resource
インスタンスで知る方法は成功しませんでした。いつものように。ところで、このメソッドはios <11では機能しません。
。script<script>
タグを使用してhtmlをロードしようとしました。 onload
とonerror
を正しく、残念ながら、Chromeでのみ発行します。
そして、あきらめる準備ができたとき、長老の同僚がhtml4タグ<object>
について教えてくれました。 <iframe>
タグに似ていますが、コンテンツがロードされない場合のフォールバックがあります。それは私たちが必要としているもののように聞こえます!残念ながら、思ったほど簡単ではありません。
コードセクション
var obj = document.createElement('object');
// we need to specify a callback (i will mention why later)
obj.innerHTML = '<div style="height:5px"><div/>'; // fallback
obj.style.display = 'block'; // so height=5px will work
obj.style.visibility = 'hidden'; // to hide before loaded
obj.data = src;
この後、iframe
でやりたいように、いくつかの属性を<object>
に設定できます。唯一の違いは、属性ではなく<params>
を使用する必要がありますが、名前と値は同じです。
for (var prop in params) {
if (params.hasOwnProperty(prop)) {
var param = document.createElement('param');
param.name = prop;
param.value = params[prop];
obj.appendChild(param);
}
}
さて、難しい部分です。多くの同じような要素と同様に、<object>
にはコールバックの仕様がないため、各ブラウザーの動作は異なります。
load
イベントを発行します。load
およびerror
を正しく発行します。iframe
、getEntriesByType
、script
。と何の違いもないようです...しかし、ネイティブブラウザのフォールバックがあります!したがって、フォールバック(innerHtml)を直接設定するため、<object>
がロードされているかどうかがわかります。
function isReallyLoaded(obj) {
return obj.offsetHeight !== 5; // fallback height
}
/**
* Chrome calls always, Firefox on load
*/
obj.onload = function() {
isReallyLoaded(obj) ? onLoaded() : onError();
};
/**
* Firefox on error
*/
obj.onerror = function() {
onError();
};
しかし、Safariで何をすべきか?古き良きsetTimeout
。
var interval = function() {
if (isLoaded) { // some flag
return;
}
if (hasResult(obj)) {
if (isReallyLoaded(obj)) {
onLoaded();
} else {
onError();
}
}
setTimeout(interval, 100);
};
function hasResult(obj) {
return obj.offsetHeight > 0;
}
ええ....それほど速くはありません。問題は、<object>
が失敗したときに仕様の動作に言及されていないことです:
そのため、コードには少し拡張が必要です
var interval = function() {
if (isLoaded) { // some flag
return;
}
if (hasResult(obj)) {
if (isReallyLoaded(obj)) {
interval.count++;
// needs less then 400ms to fallback
interval.count > 4 && onLoadedResult(obj, onLoaded);
} else {
onErrorResult(obj, onError);
}
}
setTimeout(interval, 100);
};
interval.count = 0;
setTimeout(interval, 100);
さて、ロードを開始するには
document.body.appendChild(obj);
それだけです。コードを細かく説明しようとしたので、それほど愚かではないかもしれません。
P.S。 WebDevがひどい
エラーページに対してpageshowイベントが発生すると思います。または、これをchromeから実行している場合、進行状況リスナーのリクエストをチェックして、HTTPチャンネルであるかどうかを確認します。この場合、ステータスコードを取得できます。
ページの依存関係については、キャプチャするonerrorイベントリスナーを追加することでchromeからのみこれを行うことができ、CSSの背景やその他の画像ではなく要素のエラーのみを検出します。
あなたの質問に正確には答えませんが、答えを探してここに来たので、他の誰かが私に似た質問をした場合に備えて投稿しています。
ロードイベントを使用することはあまりありませんが、Webサイトがアクセス可能かつ呼び出し可能かどうかを検出できます(アクセス可能な場合は、理論的にはiFrameをロードする必要があります)。
最初は、AJAXの呼び出しを他のすべての人と同じように行うことを考えていましたが、jQueryを使用していたため、最初は動作しませんでした。
var url = http://url_to_test.com/
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status != 200) {
console.log("iframe failed to load");
}
};
xhttp.open("GET", url, true);
xhttp.send();
編集:
したがって、この方法は正常に機能しますが、クロスオリジンマラキーにより、多くの偽陰性(iframeに表示されるものを多く拾います)があります。これを回避する方法は、サーバーでCURL/Web要求を実行し、a)Webサイトが存在する場合、およびb)ヘッダーがx-frame-options
を設定した場合、応答ヘッダーを確認することでした。
独自のWebサーバーを実行する場合は、独自のAPI呼び出しを行うことができるため、これは問題ではありません。
Node.jsでの私の実装:
app.get('/iframetest',function(req,res){ //Call using /iframetest?url=url - needs to be stripped of http:// or https://
var url = req.query.url;
var request = require('https').request({Host: url}, function(response){ //This does an https request - require('http') if you want to do a http request
var headers = response.headers;
if (typeof headers["x-frame-options"] != 'undefined') {
res.send(false); //Headers don't allow iframe
} else {
res.send(true); //Headers don't disallow iframe
}
});
request.on('error',function(e){
res.send(false); //website unavailable
});
request.end();
});
Iframeに読み込まれているページの一番上の(body)要素のIDを持っています。
iframeのLoadハンドラで、getElementById()がnull以外の値を返すかどうかを確認します。そうであれば、iframeは正常にロードされています。それ以外の場合は失敗しました。
その場合、frame.src = "about:blank"を配置します。それを行う前に、必ずロードハンドラーを削除してください。