1. 程式人生 > >HTTPS站點使用WebSocket的常見錯誤及解決方案

HTTPS站點使用WebSocket的常見錯誤及解決方案

因為HTTPS是基於SSL依靠證書來驗證伺服器的身份,併為瀏覽器和伺服器之間的通訊加密,所以在HTTPS站點呼叫某些非SSL驗證的資源時瀏覽器可能會阻止。比如使用ws://***呼叫websocket伺服器或者引入類似http://***.js的js檔案等都會報錯。這裡簡述一下連線websocket伺服器時的錯誤及解決方案。當使用ws://連線websocket伺服器時會出現類似如下錯誤:

Mixed Content: The page at '*****' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://*****'. This request has been blocked; this endpoint must be available over WSS.
(anonymous) 
Uncaught DOMException: Failed to construct 'WebSocket': An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.

如果瀏覽器不阻止,那在https站點下呼叫ssl資源才可以,面說一下解決方案:

方案一:假設HTTPS站點使用Nginx伺服器,其他伺服器也是類似的思路,可以用伺服器代理ws服務,可以用nginx的WebSocket proxying,簡述一下配置方案

#首先將客戶端請求websocket時的地址更改為wss://代理伺服器url(代理伺服器必須支援https) 例如
var ws = new WebSocket("wss://www.liminghulian.com/websocket");
#在代理伺服器上的nginx配置檔案中的server中增加如下配置項
location /websocket/ {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

#http中增加
upstream backend{
   server websocket伺服器的ip:埠;
}

這樣客戶端請求的是wss://伺服器,通過nginx的WebSocket proxying代理到實際不支援ssl的websocket伺服器。

方案二:直接為WebSocket伺服器增加ssl證書,這樣就可以直接通過wss://來請求伺服器了,以swoole為例,其他伺服器也是類似的思路,下面給出示例程式碼

//使用SSL必須在編譯swoole時加入--enable-openssl選項
$server = new Swoole\WebSocket\Server("0.0.0.0", 9502, SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
$server->set(
	[
      'ssl_cert_file' => '證書',
       'ssl_key_file' => '/usr/local/nginx/conf/cert/214517325220006.key',
	]
);
$server->on('open', function (Swoole\WebSocket\Server $server, $request) {
    echo "server: handshake success with fd{$request->fd}\n";
});

$server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
    echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
    $server->push($frame->fd, "this is server");
});

$server->on('close', function ($ser, $fd) {
    echo "client {$fd} closed\n";
});

$server->start();