2015-06-25 11 views
111

我一直在進行大量的研究並找不到處理此問題的方法。我正嘗試從https服務器執行jQuery ajax調用,並通過自定義自簽名證書運行帶有jetty的locahost https服務器。我的問題是我無法確定響應是拒絕連接還是不安全響應(由於缺少證書接受)。有沒有辦法來確定兩種情況之間的差異?該responseText,和statusCode總是在這兩種情況下是相同的,即使在Chrome控制檯我可以看到一個區別:確定是否由於不安全的響應或拒絕連接而導致ajax呼叫失敗

net::ERR_INSECURE_RESPONSE 
net::ERR_CONNECTION_REFUSED 

responseText始終是「」和statusCode始終爲「0」兩種情況。

我的問題是,如何確定是否由於ERR_INSECURE_RESPONSE或由於ERR_CONNECTION_REFUSED而導致jQuery ajax調用失敗?

一旦證書被接受,一切正常,但我想知道本地主機服務器是關閉,還是啓動並運行,但證書尚未被接受。

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

enter image description here

即使手動執行我得到同樣結果的請求:

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

我會發布我的代碼,但它不是一個javascript代碼錯誤。請仔細閱讀我的問題。 – taxicala

+1

另外兩個錯誤回調參數是否給出了額外的見解? 'function(xhr,status,msg){...'我懷疑他們會這樣做,但值得嘗試。 –

+0

您是否在不同的瀏覽器中看到不同的錯誤代碼?這可能是由Chrome生成和阻止的。 – Jasen

回答

59

有沒有辦法從區分開來最新的Web瀏覽器。

W3C規範:

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.

正如你可以看到,網絡錯誤不包括HTTP響應,其中包括錯誤的,這就是爲什麼你總是0獲得作爲狀態碼,而「」的錯誤。

Source


注意:使用谷歌的Chrome版本43.0.2357.130作了下面的例子和反對,我已經可以模擬OP一個環境。代碼設置在答案的底部。


我雖然是一種方法來解決,這將是使通過HTTP的二次請求,而不是HTTPS作爲This answer,但我記得這是不可能的,因爲該瀏覽器的新版本阻止混合內容。

這意味着如果您使用HTTPS,Web瀏覽器將不允許通過HTTP請求,反之亦然。

從幾年前就已經是這樣了,但老版本的Web瀏覽器版本比如Mozilla Firefox在它下面版本23允許它。

證據看:

使從HTTP請求HTTPS usign網絡Broser控制檯

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

將導致以下錯誤:

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.

同樣的錯誤將出現在瀏覽器控制檯,如果您嘗試以其他方式添加Iframe來完成此操作。

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

使用Socket連接也Posted as an answer,我敢肯定,其結果將是相同/相似的,但我已經給它一個嘗試。

嘗試打開從Web Broswer使用HTTPS到非安全套接字端點的套接字連接將以混合內容錯誤結束。

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.

然後我試圖連接到WSS端點也看到如果我可以閱讀有關網絡連接錯誤的一些信息:

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

執行上面的代碼中使用服務器關閉的結果:

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

在打開服務器的情況下執行上面的代碼片段

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

但是,「onerror函數」輸出到控制檯的錯誤沒有任何技巧來區分另一個錯誤。


使用代理作爲this answer suggest可以工作,但只有在「目標」服務器的公共訪問。

這不是這種情況,所以試圖在這種情況下實現代理將導致我們遇到同樣的問題。

代碼來創建Node.js的HTTPS服務器

我已經創建了兩個HTTPS的NodeJS服務器,使用自簽名證書:

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中。

要運行它只需在終端(ubuntu示例)中執行node applicationServer.jsnode targetServer.js

+5

這是迄今爲止最完整的答案。它表明你實際上已經完成了一些研究工作和測試。我看到你已經嘗試過所有可能的方式來執行此操作,並且所有場景都很好解釋。您還提供了示例代碼來快速設置測試環境!真的很好!感謝您的洞察! – taxicala

29

截至目前:沒有辦法區分的browers之間的這種事件。由於瀏覽器不提供開發人員訪問的事件。(2015年7月)

這個答案只是爲潛在的,albiet hacky和不完整的解決方案提供想法。


免責聲明:這個答案是不完整的,因爲它不完全解決 OP的問題(由於跨域策略)。然而,這個想法本身確實具有一些優點,這些優點被進一步擴展:@artur grzesiak here,使用代理和ajax。


相當多的研究之後我自己,似乎沒有被檢查連接的區別是任何形式的錯誤的拒絕和不安全的響應,至少就如JavaScript提供的不同的響應兩者之間。

我的研究普遍認爲SSL證書是由瀏覽器處理的,因此,除非用戶接受自簽名證書,否則瀏覽器會鎖定所有請求,包括狀態碼的所有請求。瀏覽器可以(如果編碼的話)發送回它自己的狀態代碼以獲得不安全的響應,但是這對於任何事情都沒有幫助,即使如此,瀏覽器兼容性問題(Chrome/Firefox/IE具有不同的標準。 ..再次)

由於您的原始問題是檢查您的服務器之間的狀態與正在上升與有一個未被接受的證書,你可以不這樣做一個標準的HTTP請求?

isUp = false; 
isAccepted = false; 

var isUpRequest = new XMLHttpRequest(); 
isUpRequest.open('GET', "http://localhost/custom/server/", true); //note non-ssl port 
isUpRequest.onload = function() { 
    isUp = true; 
    var isAcceptedRequest = new XMLHttpRequest(); 
    isAcceptedRequest.open('GET', "https://localhost/custom/server/", true); //note ssl port 
    isAcceptedRequest.onload = function() { 
     console.log("Server is up and certificate accepted"); 
     isAccepted = true; 
    } 
    isAcceptedRequest.onerror = function() { 
     console.log("Server is up and certificate is not accepted"); 
    } 
    isAcceptedRequest.send(); 
}; 
isUpRequest.onerror = function() { 
    console.log("Server is down"); 
}; 
isUpRequest.send(); 

當然,這確實需要一個額外的請求來驗證服務器連接,但它應該通過消除過程來完成工作。儘管如此,我仍然覺得很不舒服,而且我並不是那種加倍要求的忠實粉絲。

+6

我讀過整個答案,我不認爲這會起作用。我的兩臺服務器都運行HTTPS,這意味着此時我向HTTP服務器發出請求,瀏覽器將立即取消它,因爲您無法向HTTP服務器發送從HTTPS服務器發出的Ajax請求 – taxicala

11

@ Schultzie的回答非常接近,但顯然http - 一般來說 - 在瀏覽器環境下不會起作用https

您可以做的是使用中間服務器(代理)代表您提出請求。代理應該允許從https來源轉發http請求或從自簽名來源加載內容。

有適當的證書自己的服務器可能是你的情況矯枉過正 - 你可以使用自簽名證書,而不是使用機器此設置 - 但有很多匿名開放代理服務出那裏。

這樣,我想起這兩種方法是:

  1. Ajax請求 - 在這種情況下,代理必須使用適當的設置CORS
  2. 使用iframe - 你通過代理加載腳本(可能用html包裹)在iframe中。一旦腳本加載,它會向其.parentWindow發送一條消息。如果你的窗口收到一條消息,你可以確定服務器正在運行(或者更確切地說,是在運行幾分之一秒之前)。

如果你只對本地環境有興趣,你可以嘗試使用--disable-web-security標誌運行鉻。


另一個建議:你是否嘗試以編程方式加載圖像,以確定是否存在更多信息?

2

退房jQuery.ajaxError() 取出的參考來源:jQuery AJAX Error Handling (HTTP Status Codes) 它抓住,你可以在任何數量的方式通過HTTP或HTTPS處理全局阿賈克斯的錯誤:

if (jqXHR.status == 501) { 
//insecure response 
} else if (jqXHR.status == 102) { 
//connection refused 
} 
+0

這與做ajax就像我這樣做,但集中在一個地方的錯誤響應。 – taxicala

+1

問題是,當ajax調用發生時,證書沒有加載,因爲它似乎是問題所在。任何方式gl找到答案:) – Varshaan

+2

不,問題是,我想確定必須接受證書,並知道服務器是否關閉之間的差異。 – taxicala

1

不幸的是,現在的瀏覽器XHR API沒有提供明確的指示,說明瀏覽器由於「不安全的響應」而拒絕連接,以及它不信任網站的HTTP/SSL證書時。

但是有辦法解決這個問題。

我想出一個解決方案來確定瀏覽器何時不信任HTTP/SSL證書,首先要檢測是否發生了XHR錯誤(例如,使用jQuery error()回調),然後檢查XHR調用到'https://'URL,然後檢查XHR readyState是否爲0,這意味着XHR連接甚至沒有打開(當瀏覽器不喜歡證書時會發生這種情況)。

這裏就是我這樣做的代碼: https://github.com/maratbn/RainbowPayPress/blob/e9e9472a36ced747a0f9e5ca9fa7d96959aeaf8a/rainbowpaypress/js/le_requirejs/public/model_info__transaction_details.js#L88

1

我不認爲有目前一種方法來檢測這些錯誤信息,但黑客工具,你能做的就是在前面使用服務器類似的nginx您的應用程序服務器,以便如果應用程序服務器關閉,您將從nginx獲得一個錯誤的網關錯誤,您可以在JS中檢測到502狀態代碼。否則,如果證書無效,您仍然會收到與statusCode = 0相同的通用錯誤。

相關問題