没有办法将其与最新的Web浏览器区分开来。
W3C 规格:
以下步骤描述了用户代理必须为简单的跨域请求执行的操作:
应用“提出请求”步骤,并在发出请求时遵守以下请求规则。
如果未设置手动重定向标志,并且响应的 HTTP 状态代码为 301、302、303、307 或 308应用重定向步骤。
如果最终用户取消请求应用中止步骤。
如果存在网络错误如果出现 DNS 错误、TLS 协商失败或其他类型的网络错误,请应用网络错误步骤。不要请求任何类型的最终用户交互。
注意:这不包括指示某种类型的错误的 HTTP 响应,例如 HTTP 状态代码 410。
否则执行资源共享检查。如果返回失败,请应用网络错误步骤。否则,如果返回 pass,则终止此算法并将跨源请求状态设置为成功。不要实际终止请求。
如您所见,网络错误不包括包含错误的HTTP响应,这就是为什么您将始终获得0作为状态代码,“”作为错误。
源
注意:以下示例是使用Google Chrome版本43.0.2357.130针对我创建的模拟OP one的环境制作的。设置它的代码在答案的底部。
我虽然一种方法来解决这个问题是通过HTTP而不是HTTPS发出辅助请求作为这个答案,但我记得这是不可能的,因为较新版本的浏览器会阻止混合内容。
这意味着,如果您使用的是HTTPS,则Web浏览器将不允许通过HTTP进行请求,反之亦然。
自几年前以来一直如此,但是较旧的Web浏览器版本(例如其下面的Mozilla Firefox)版本23允许它。
关于它的证据:
从 HTTPS usign Web Broser 控制台发出 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>
使用Socket连接也被发布为答案,我很确定结果将是相同/相似的,但我已经试过了。
尝试使用 HTTPS 打开从 Web 浏览器到非安全套接字终结点的套接字连接将以混合内容错误告终。
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);
}
在关闭服务器的情况下执行上面的代码段会导致:
与“wss://localhost:8001/”的 WebSocket 连接失败: 连接建立错误: net::ERR_CONNECTION_REFUSED
在服务器打开的情况下执行上面的代码段
与“wss://localhost:8001/”的 WebSocket 连接失败:WebSocket 打开握手已取消
但同样,“onerror函数”输出到控制台的错误没有任何提示来区分一个错误。
按照这个答案的建议使用代理可以工作,但前提是“目标”服务器具有公共访问权限。
这里的情况并非如此,因此在这种情况下尝试实现代理将导致我们遇到同样的问题。
创建节点.js HTTPS 服务器的代码:
我已经创建了两个Nodejs HTTPS服务器,它们使用自签名证书:
目标服务器.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);
应用程序服务器.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中。
要运行它,只需执行并在终端中(ubuntu示例)。node applicationServer.js
node targetServer.js