不正なリクエストではなく、クロスオリジンエラーが原因でXMLHttpRequest()が失敗したことを検出しようとしています。例えば:
ajaxObj=new XMLHttpRequest()
ajaxObj.open("GET", url, true);
ajaxObj.send(null);
URLの4つのケースを考慮してください。
事例1: urlは、access-control-allow-Originが適切に設定されている有効なアドレスです
http://192.168.8.35
私がサーバーを持っている場所Access-Control-Allow-Origin: *
ヘッダーに設定ケース2: urlは既存のサーバーの無効なアドレスです
http://xyz.google.com
サーバーは応答しますが、有効な要求ではありませんケース3: urlは存在しないサーバーのIPアドレスです
http://192.168.8.6
応答するものがないローカルネットワーク上ケース4: urlは、access-control-allow-Originが有効なアドレスです ない セット
http://192.168.8.247
サーバーがある場所 なしで Access-Control-Allow-Origin: *
ヘッダーに設定問題は: ケース4(access-control-allow-Originエラー)とケース2&3を区別するにはどうすればよいですか?
ケース4では、Chromeデバッグコンソールにエラーが表示されます。
XMLHttpRequest cannot load http://192.168.8.247/. Origin http://localhost is not allowed by Access-Control-Allow-Origin.
Javascriptでそのエラーを知らせるにはどうすればよいですか?
ajaxObj
で何らかの兆候を見つけようとしましたが、ケース2と3と比較して違いはないようです。
ここに私が使用した簡単なテストがあります:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>CORS Test</title>
<script type="text/javascript">
function PgBoot()
{
// doCORS("http://192.168.8.35"); // Case 1
// doCORS("http://xyz.google.com"); // Case 2
doCORS("http://192.168.8.6"); // Case 3
// doCORS("http://192.168.8.247"); // Case 4
}
function doCORS(url)
{
document.getElementById("statusDiv").innerHTML+="Processing url="+url+"<br>";
var ajaxObj=new XMLHttpRequest();
ajaxObj.overrideMimeType('text/xml');
ajaxObj.onreadystatechange = function()
{
var stat=document.getElementById("statusDiv");
stat.innerHTML+="readyState="+ajaxObj.readyState;
if(ajaxObj.readyState==4)
stat.innerHTML+=", status="+ajaxObj.status;
stat.innerHTML+="<br>";
}
ajaxObj.open("GET", url, true);
ajaxObj.send(null);
}
</script>
</head>
<body onload="PgBoot()">
<div id="statusDiv"></div>
</body>
</html>
Chromeを使用した結果:
Processing url=http://192.168.8.35
readyState=1
readyState=2
readyState=3
readyState=4, status=200
Processing url=http://xyz.google.com
readyState=1
readyState=4, status=0
Processing url=http://192.168.8.6
readyState=1
readyState=4, status=0
Processing url=http://192.168.8.247
readyState=1
readyState=4, status=0
いいえ、W3C仕様によると、違いを見分ける方法はありません。
以下に、CORS仕様で 単純なクロスオリジンリクエスト プロシージャを指定する方法を示します。
リクエストの作成手順を適用し、リクエストの作成中に以下のリクエストルールを遵守します。
手動リダイレクトフラグが設定されておらず、応答のHTTPステータスコードが301、302、303、307、または308の場合:リダイレクト手順を適用します。
エンドユーザーがリクエストをキャンセルした場合:中止ステップを適用します。
ネットワークエラーがある場合:DNSエラー、TLSネゴシエーション失敗、またはその他のタイプの場合ネットワークエラーの場合、ネットワークエラーステップを適用します。エンドユーザーとの対話を要求しないでください...
それ以外の場合:リソース共有チェックを実行します。 失敗が返された場合、ネットワークエラー手順を適用します...
失敗したネットワーク接続または失敗したCORS交換の場合、 network error steps が適用されるため、文字通り2つのケースを区別する方法はありません。
どうして? 1つの利点は、攻撃者がLANのネットワークトポロジを検査するのを防ぐことです。たとえば、悪意のあるWebページスクリプトは、HTTPインターフェースをリクエストすることでルーターのIPアドレスを見つけることができるため、ネットワークトポロジに関するいくつかのこと(たとえば、プライベートIPブロックの大きさ、/8
または/16
)。ルーターはCORSヘッダーを送信しない(または送信しない)ため、スクリプトはまったく何も学習しません。
たぶんそれが誰かを助ける場合... corsとネットワークエラーの違いを処理するもう1つの方法... chromeまたはfirefox ...で動作します...
var external = 'your url';
if (window.fetch) {
// must be chrome or firefox which have native fetch
fetch(external, {'mode':'no-cors'})
.then(function () {
// external is reachable; but failed due to cors
// fetch will pass though if it's a cors error
})
.catch(function () {
// external is _not_ reachable
});
} else {
// must be non-updated safari or older IE...
// I don't know how to find error type in this case
}
CORS違反を他の失敗したAJAXリクエストと区別するために、)サーバーを使用してHEADリクエストのレスポンスヘッダーを調べることができます-side codeを実行し、クライアントページに結果を返します。たとえば、AJAXリクエストが失敗した場合(ステータス0)、このスクリプトを呼び出すことができます( cors.php
)と呼び、応答ヘッダーにAccess-Control-*
ヘッダーが含まれているかどうかを確実に確認します。
例:
cors.php?url = http://ip.jsontest.com
cors.php?url = http://www.google.com
cors.php?url = http://10.0.0.1
返す
HTTP/1.1 200 OK Access-Control-Allow-Origin:*
HTTP/1.1 302が見つかりました
無効なリクエスト
cors.php-必要に応じてカスタマイズする
<?php /* cors.php */
$url = $_GET["url"];
if(isset($url)) {
$headers = getHeaders($url);
header("Access-Control-Allow-Origin: *");
if(count($headers) == 0) {
die("Invalid request"); // cURL returns no headers on bad urls
} else {
echo $headers[0]; // echo the HTTP status code
}
// Include any CORS headers
foreach($headers as $header) {
if(strpos($header, "Access-Control") !== false) {
echo " " . $header;
}
}
}
function getHeaders($url, $needle = false) {
$headers = array();
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 4); // Timeout in seconds
curl_setopt($ch, CURLOPT_TIMEOUT, 4); // Timeout in seconds
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'HEAD'); // HEAD request only
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function($curl, $header) use(&$headers) {
array_Push($headers, $header);
return strlen($header);
});
curl_exec($ch);
return $headers;
} /* Drakes, 2015 */
クライアント側のテストハーネス:
function testCORS(url, $elem) {
$.ajax({
url: url,
timeout: 4000
})
.fail(function(jqXHR, textStatus) {
if(jqXHR.status === 0) {
// Determine if this was a CORS violation or not
$.ajax({
context: url,
url: "http://myserver.com/cors.php?url=" + escape(this.url),
})
.done(function(msg) {
if(msg.indexOf("HTTP") < 0) {
$elem.text(url + " - doesn't exist or timed out");
} else if(msg.indexOf("Access-Control-Allow-Origin") >= 0) {
$elem.text(url + " - CORS violation because '" + msg + "'");
} else {
$elem.text(url + " - no Access-Control-Allow-Origin header set");
}
});
} else {
// Some other failure (e.g. 404), but not CORS-related
$elem.text(url + " - failed because '" + responseText + "'");
}
})
.done(function(msg) {
// Successful ajax request
$elem.text(this.url + " - OK");
}); /* Drakes, 2015 */
}
ハーネスドライバー:
// Create a div and append the results of the URL calls
$div = $("<div>");
$("body").append($div);
var urls = ["http://ip.jsontest.com", "http://google.com", "http://10.0.0.1"];
urls.map( function(url) {
testCORS(url, $div.append("<h4>").children().last());
});
結果:
http://ip.jsontest.com-OK
http://google.com-Access-Control-Allow-Originヘッダーセットなし
http://10.0.0.1-存在しないか、タイムアウトしていません
驚くべきことに、あなたは画像に対してそれを行うことができます(そして、おそらく他の特定のコンテンツタイプにも同様の解決策があります)。トリックは、明らかにCORSを考慮しないということです。したがって、ステートメント"urlはXHRによるロードに失敗します&& urlはimg srcによるロードに成功します"は、URLは機能するがCORSがブロックされることを意味します.
これはすべての場合に間違いなく役立つわけではありませんが、場合によっては(たとえば、ユーティリティが適切にCORSを渡しているかどうかを検出するなど)トリックを行う場合があります。たとえば、サーバーにバックエンドの正しく構成されたURLと誤って構成されたCORSを使用してアプリ(個別のフロントエンドとバックエンド)がインストールされている場合、コンソールで警告を発したかったので、テストするイメージを提供できるのでこれで十分でしたに。
function testCors(url) {
var myRequest = new XMLHttpRequest();
myRequest.open('GET', url, true);
myRequest.onreadystatechange = () => {
if (myRequest.readyState !== 4) {
return;
}
if (myRequest.status === 200) {
console.log(url, 'ok');
} else {
var myImage = document.createElement('img');
myImage.onerror = (...args) => {console.log(url, 'other type of error', args);}
myImage.onload = () => {console.log(url, 'image exists but cors blocked');}
myImage.src = url;
console.log(url, 'Image not found');
}
};
myRequest.send();
}
これが私がしたことです-ただし、リモートサーバーに変更を加える必要があります(ページを追加します)。
ただし、どちらの方法でもパラメーターを渡す場合、安全にすることは非常に難しいことに注意してください(だれでもiframeを埋め込むことができます。
また、完全ではありません(一時的な一時的ではないエラーのみを検出します)。
ただし、多くの作業がありますが、エラーの原因に関する詳細情報を取得できます。ユーザーのブラウザに直接アクセスできない場合に非常に便利です。
PS:これは、PHP回答とはまったく異なります。回答は、サーバーがリモートサーバーと通信する必要があることを示唆しています。(a)通信障害の原因の診断にはあまり使用されません。 from PHPは、サーバーが真剣に使用されていることを要求しているだけです!