确定ajax调用是否由于不安全的响应或连接被拒绝而失败 [英] Determine if ajax call failed due to insecure response or connection refused

查看:512
本文介绍了确定ajax调用是否由于不安全的响应或连接被拒绝而失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在做大量的研究,找不到一个办法来处理这个。我试图执行一个jQuery ajax调用从https服务器到locahost https服务器运行jetty与自定义自签名证书。我的问题是,我不能确定响应是拒绝连接还是不安全响应(由于缺少证书接受)。有没有办法来确定这两种情况之间的区别?在这两种情况下, responseText statusCode 总是相同的,即使在Chrome控制台中我可以看到差异:

  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){
//做某事
},
错误:function(xhr,textStatus,errorThrown){
console.log(xhr,textStatus, errorThrown); //对于拒绝和不安全的响应总是相同的。
}
});



即使手动执行请求,我也会得到相同的结果:

  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();


解决方案


以区别于最新的网络浏览器。



W3C规格:


下面的步骤描述了用户代理对于简单的跨源请求必须执行的操作:



应用提出请求



如果手动重定向标志未设置,并且响应的HTTP状态代码为301,302, 303,307或308
应用重定向步骤。



如果最终用户取消请求 $ b 如果出现网络错误
如果发生DNS错误,TLS协商失败或其他类型的网络错误,请应用网络错误步骤。不要请求任何类型的最终用户互动。



注意:这不包括指示某种类型错误的HTTP响应,例如HTTP状态代码410。



否则
执行资源共享检查。如果返回失败,请应用网络错误步骤。否则,如果返回pass,则终止此算法并将跨源请求状态设置为success。


正如您所看到的,网络错误不包括包含错误的HTTP响应是为什么您会始终将0作为状态代码,并将作为错误。



来源






注意:以下示例是使用Google Chrome版本43.0.2357.130以及我为了模拟OP one创建的环境而创建的。






我认为一种方法要解决这个问题请通过HTTP(而不是HTTPS)作为辅助请求,请此回答,但我记得,由于较新的版本的浏览器会阻止混合内容。



这意味着如果您使用HTTPS,Web浏览器将不允许通过HTTP发送请求,反之亦然。



从几年前就一直这样,但是旧版的Web浏览器版本,比如Mozilla Firefox下面的版本23允许。



有关此问题的证据:



通过HTTPS从Web控制台发出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 / 的页面已加载,但请求了一个不安全的XMLHttpRequest端点 http:// localhost:8001 / 。此请求已被阻止;内容必须通过HTTPS提供。


如果您尝试以其他方式添加iframe。

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






使用Socket连接也是发布为答案,我很确定的结果将是相同/类似,但我试试。



尝试从Web Broswer使用HTTPS打开套接字连接到非安全套接字端点将导致混合内容错误。

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




1)混合内容: https:// localhost:8000 / '通过HTTPS加载,但尝试连接到不安全的WebSocket端点'ws:// localhost:8001 /'。此请求已被阻止;这个端点必须通过WSS可用。



2)未捕获DOMException:无法构造'WebSocket':不可能从通过HTTPS加载的页面启动不安全的WebSocket连接。


然后我试图连接到一个wss端点也看到如果我可以读一些关于网络连接错误的信息:

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

在服务器关闭时执行上面的代码段会导致:


WebSocket连接到wss:// localhost:8001 /'失败:连接建立错误:net :: ERR_CONNECTION_REFUSED


< blockquote>

在服务器开启时执行上面的代码片段


WebSocket连接到'wss:// localhost:8001 /'failed:WebSocket打开握手已取消


但是,onerror函数没有任何提示来区分另一个错误。






使用代理作为这个回答建议可以工作,但只有当目标服务器具有公共访问权限。



这里不是这样,所以试图在这种情况下实现一个代理会导致我们同样的问题。



创建Node.js HTTPS服务器的代码



两个使用自签名证书的Nodejs HTTPS服务器:



targetServer.js:

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

var options = {
key:fs.readFileSync('./ certs2 / key.pem'),
cert:fs.readFileSync('./ certs2 / 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\\\
);
})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\\\
);
})。listen(8000);

要使其工作,您需要安装Nodejs,需要为每个服务器和存储生成单独的证书



要运行它只需执行节点applicationServer.js 节点targetServer.js (ubuntu示例)。


I've been doing a lot of research and could not find a way to handle this. I'm trying to perform a jQuery ajax call from an https server to a locahost https server running jetty with a custom self signed certificate. My problem is that I cannot determine whether the response is a connection refused or a insecure response (due to the lack of the certificate acceptance). Is there a way to determine the difference between both scenarios? The responseText, and statusCode are always the same in both cases, even though in the chrome console I can see a difference:

net::ERR_INSECURE_RESPONSE
net::ERR_CONNECTION_REFUSED

responseText is always "" and statusCode is always "0" for both cases.

My question is, how can I determine if a jQuery ajax call failed due to ERR_INSECURE_RESPONSE or due to ERR_CONNECTION_REFUSED?

Once the certificate is accepted everything works fine, but I want to know whether the localhost server is shut down, or its up and running but the certificate has not yet been accepted.

$.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.
    }
});

Even performing manually the request I get the same result:

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();

解决方案

There is no way to differentiate it from newest Web Browsers.

W3C Specification:

The steps below describe what user agents must do for a simple cross-origin request:

Apply the make a request steps and observe the request rules below while making the request.

If the manual redirect flag is unset and the response has an HTTP status code of 301, 302, 303, 307, or 308 Apply the redirect steps.

If the end user cancels the request Apply the abort steps.

If there is a network error In case of DNS errors, TLS negotiation failure, or other type of network errors, apply the network error steps. Do not request any kind of end user interaction.

Note: This does not include HTTP responses that indicate some type of error, such as HTTP status code 410.

Otherwise Perform a resource sharing check. If it returns fail, apply the network error steps. Otherwise, if it returns pass, terminate this algorithm and set the cross-origin request status to success. Do not actually terminate the request.

As you can read, network errors does not include HTTP response that include errors, that is why you will get always 0 as status code, and "" as error.

Source


Note: The following examples were made using Google Chrome Version 43.0.2357.130 and against an environment that I've created to emulate OP one. Code to the set it up is at the bottom of the answer.


I though that an approach To work around this would be make a secondary request over HTTP instead of HTTPS as This answer but I've remembered that is not possible due that newer versions of browsers block mixed content.

That means that the Web Browser will not allow a request over HTTP if you are using HTTPS and vice versa.

This has been like this since few years ago but older Web Browser versions like Mozilla Firefox below it versions 23 allow it.

Evidence about it:

Making a HTTP request from HTTPS usign Web Broser console

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();

will result in the following error:

Mixed Content: The page at 'https://localhost:8000/' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://localhost:8001/'. This request has been blocked; the content must be served over HTTPS.

Same error will appear in the browser console if you try to do this in other ways as adding an Iframe.

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


Using Socket connection was also Posted as an answer, I was pretty sure that the result will be the same / similar but I've give it a try.

Trying to Open a socket connection from the Web Broswer using HTTPS to a non Secure socket endpoint will end in mixed content errors.

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

1) Mixed Content: The page at 'https://localhost:8000/' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://localhost:8001/'. This request has been blocked; this endpoint must be available over WSS.

2) Uncaught DOMException: Failed to construct 'WebSocket': An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.

Then I've tried to connect to a wss endpoint too see If I could read some information about network connection errors:

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

Executing snippet above with Server turned off results in:

WebSocket connection to 'wss://localhost:8001/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED

Executing snippet above with Server turned On

WebSocket connection to 'wss://localhost:8001/' failed: WebSocket opening handshake was canceled

But again, the error that the "onerror function" output to the console have not any tip to differentiate one error of the other.


Using a proxy as this answer suggest could work but only if the "target" server has public access.

This was not the case here, so trying to implement a proxy in this scenario will lead Us to the same problem.

Code to create Node.js HTTPS server:

I've created two Nodejs HTTPS servers, that use self signed certificates:

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);

To make it work you need to have Nodejs Installed, Need to generate separated certificates for each server and store it in the folders certs and certs2 accordingly.

To Run it just execute node applicationServer.js and node targetServer.js in a terminal (ubuntu example).

这篇关于确定ajax调用是否由于不安全的响应或连接被拒绝而失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆