1. ホーム
  2. javascript

[解決済み] 安全でないレスポンスや接続拒否によりajaxコールが失敗したかどうかを判断する

2022-08-26 10:26:10

質問

いろいろと調べてみたのですが、これを処理する方法が見つかりませんでした。私はhttpsサーバーからjettyを実行しているlocahost httpsサーバーへのjQuery ajaxコールをカスタム自己署名証明書で実行しようとしています。私の問題は、応答が接続拒否または安全でない応答(証明書の受け入れがないため)であるかどうかを判断できないことです。両方のシナリオの違いを判断する方法はありますか?その responseTextstatusCode は、クロームコンソールでは違いが見えるのに、どちらも常に同じです。

net::ERR_INSECURE_RESPONSE
net::ERR_CONNECTION_REFUSED

responseText は常に ""であり statusCode は常に "0"となります。

私の質問は、jQueryのajaxコールが、以下の理由で失敗したかどうかを判断する方法です。 ERR_INSECURE_RESPONSE が原因なのか ERR_CONNECTION_REFUSED ?

証明書が承認されると、すべてがうまく機能しますが、ローカルホスト サーバーがシャットダウンされているのか、それとも稼働しているが証明書がまだ承認されていないのかを知りたいのです。

$.ajax({
    type: 'GET',
    url: "https://localhost/custom/server/",
    dataType: "json",
    async: true,
    success: function (response) {
        //do something
    },
    error: function (xhr, textStatus, errorThrown) {
        console.log(xhr, textStatus, errorThrown); //always the same for refused and insecure responses.
    }
});

<イグ

手動でリクエストを行っても、同じ結果になります。

var request = new XMLHttpRequest();
request.open('GET', "https://localhost/custom/server/", true);
request.onload = function () {
    console.log(request.responseText);
};
request.onerror = function () {
    console.log(request.responseText);
};
request.send();

どのように解決するのですか?

最新の Web ブラウザと区別する方法がありません。

W3Cの仕様です。

以下のステップは、単純なクロスオリジンリクエストのために、ユーザエージェントが何をしなければならないかを記述しています。 :

リクエストの作成手順を適用し、リクエストの作成中に以下のリクエストルールを守ってください。

手動リダイレクトフラグが設定されておらず、レスポンスのHTTPステータスコードが301、302、303、307、または308である場合 リダイレクトの手順を適用してください。

エンドユーザがリクエストをキャンセルした場合 中止のステップを適用します。

ネットワークエラーが発生した場合 DNSエラーやTLSネゴシエーション失敗など、ネットワークエラーが発生した場合は、以下のように ネットワークエラーの手順 . エンドユーザーとの対話は一切要求しないでください。

注意: HTTP ステータスコード 410 のような、何らかのエラーを示す HTTP レスポンスは含まれません。

その他 リソース共有チェックを行う。失敗を返した場合は、ネットワークエラーの手順を適用する。それ以外の場合、pass を返したら、このアルゴリズムを終了して cross-origin リクエストのステータスを success に設定する。実際にはリクエストを終了させないでください。

読んで字の如く、ネットワークエラーはエラーを含むHTTPレスポンスを含まないため、ステータスコードは常に0、エラーは""となります。

ソース


注意 : 以下の例は、Google Chrome バージョン 43.0.2357.130 を使用し、OP1をエミュレートするために作成した環境に対して作成したものです。セットアップのためのコードは回答の最下部にあります。


私は、これを回避するためのアプローチは、HTTPSの代わりにHTTPでセカンダリリクエストを作成することであると思いました。 この回答は を使用することですが、新しいバージョンのブラウザは混合コンテンツをブロックするため、それは不可能であると記憶しています。

つまり、Web ブラウザは、HTTPS を使用している場合は HTTP でのリクエストを許可せず、その逆もまた然りということです。

これは数年前からのことですが、Mozilla Firefox のバージョン 23 より下のような古い Web ブラウザでは、これを許可しています。

それについての証拠。

Web Broserコンソールを使用してHTTPSからHTTPリクエストを行う。

var request = new XMLHttpRequest();
request.open('GET', "http://localhost:8001", true);
request.onload = function () {
    console.log(request.responseText);
};
request.onerror = function () {
    console.log(request.responseText);
};
request.send();

を実行すると、次のようなエラーが発生します。

ミックスコンテンツです。のページは、' https://localhost:8000/ ' のページは HTTPS で読み込まれましたが、安全でない XMLHttpRequest のエンドポイントである ' http://localhost:8001/ '. このリクエストはブロックされました。コンテンツは HTTPS で提供する必要があります。

Iframeを追加するなどの他の方法でこれを実行しようとすると、ブラウザのコンソールに同じエラーが表示されます。

<iframe src="http://localhost:8001"></iframe>


ソケット接続を使用することも 回答として投稿 ということで、同じような結果になることは間違いないのですが、一応試してみました。

HTTPS を使用して Web Broswer から非セキュア ソケット エンドポイントにソケット接続を開こうとすると、ミックス コンテンツ エラーで終わります。

new WebSocket("ws://localhost:8001", "protocolOne");

1) 混在するコンテンツ のページは https://localhost:8000/ のページは HTTPS で読み込まれましたが、安全でない WebSocket エンドポイント 'ws://localhost:8001/' に接続しようとしました。このエンドポイントは WSS 上で利用可能である必要があります。

2) キャッチされない DOMException。WebSocket'の構築に失敗しました。安全でないWebSocket接続は、HTTPSで読み込まれたページから開始されないかもしれません。

それから、私はネットワーク接続エラーに関するいくつかの情報を読むことができるかどうかを確認するために、wssエンドポイントに接続しようとしました。

var exampleSocket = new WebSocket("wss://localhost:8001", "protocolOne");
exampleSocket.onerror = function(e) {
    console.log(e);
}

上記のスニペットをServerをOFFにして実行した結果。

wss://localhost:8001/' への WebSocket 接続に失敗しました。接続の確立でエラーが発生しました: net::ERR_CONNECTION_REFUSED

サーバーをOnにして上記のスニペットを実行する

<ブロッククオート

wss://localhost:8001/' への WebSocket 接続に失敗しました。WebSocketのオープニングハンドシェイクがキャンセルされました。

しかし、再度、"onerror function"がコンソールに出力するエラーは、他のエラーと区別するためのヒントがありません。


プロキシを使用して この回答では は動作しますが、ターゲットサーバがパブリックアクセスである場合のみです。

これはこのケースではないので、このシナリオでプロキシを実装しようとすると、私たちは同じ問題に直面することになります。

Node.jsのHTTPSサーバを作成するコード :

自己署名証明書を使用する2つのNodejs HTTPSサーバを作成しました。

targetServer.js。

var https = require('https');
var fs = require('fs');

var options = {
    key: fs.readFileSync('./certs2/key.pem'),
    cert: fs.readFileSync('./certs2/key-cert.pem')
};

https.createServer(options, function (req, res) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
    res.writeHead(200);
    res.end("hello world\n");
}).listen(8001);

applicationServer.jsを使用します。

var https = require('https');
var fs = require('fs');

var options = {
    key: fs.readFileSync('./certs/key.pem'),
    cert: fs.readFileSync('./certs/key-cert.pem')
};

https.createServer(options, function (req, res) {
    res.writeHead(200);
    res.end("hello world\n");
}).listen(8000);

これを動作させるには、Nodejsをインストールし、各サーバーごとに別々の証明書を生成し、それに応じてcertsとcerts2フォルダに格納する必要があります。

実行するには、以下のコマンドを実行するだけです。 node applicationServer.jsnode targetServer.js をターミナルで表示します(ubuntuの例)。