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