Dado que HTTPS se basa en SSL para verificar la identidad del servidor mediante certificados y cifrar la comunicación entre el navegador y el servidor, el navegador puede bloquear ciertos recursos que no utilizan SSL cuando se usan en sitios HTTPS. Por ejemplo, al intentar conectar a un servidor WebSocket mediante ws:// o incluir archivos JavaScript desde http://, se pueden producir errores. A continuación, se describen los errores comunes al conectar a servidores WebSocket y sus soluciones.
Al utilizar ws:// para conectar con un servidor WebSocket en un sitio HTTPS, pueden aparecer errores similares a estos:
Contenido Mixto: La página '' se cargó mediante HTTPS, pero intentó conectarse al endpoint WebSocket inseguro 'ws://'. Esta solicitud ha sido bloqueada; este endpoint debe estar disponible mediante WSS. (anonymous) Uncaught DOMException: No se pudo construir 'WebSocket': No se puede iniciar una conexión WebSocket insegura desde una página cargada a través de HTTPS.
Si el navegador no bloqueara estas conexiones, solo sería posible llamar a recursos SSL desde un sitio HTTPS. A continuación, se presenten las soluciones:
Solución 1: Proxy de WebSocket mediante Nginx
Si el sitio HTTPS utiliza un servidor Nginx (el proceso es similar en otros servidores), se puede configurar un proxy para el servicio WebSocket. A continuación, se detalla la configuración:
# Primero, modificar la dirección WebSocket en el cliente para usar wss://url_del_proxy (el proxy debe soportar https)
var socket = new WebSocket("wss://www.ejemplo-proxy.com/websocket");
# En el archivo de configuración de Nginx del servidor proxy, añadir las siguientes directivas dentro del bloque server:
location /websocket/ {
proxy_pass http://servidor_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
# Añadir en la sección http:
upstream servidor_backend{
ip_servidor_websocket:puerto;
}
De esta forma, el cliente solicita a wss://servidor, y Nginx actúa como proxy hacia el servidor WebSocket real que no soporta SSL.
Solución 2: Implementación SSL directa en el serviodr WebSocket
Se puede agregar un certificado SSL directamente al servidor WebSocket para permitir conexiones wss:// directas. A continuación, se muestra un ejemplo con Swoole (el proceso es similar en otros servidores):
// Para usar SSL con Swoole, es necesario compilar con la opción --enable-openssl
$wservidor = new Swoole\WebSocket\Server("0.0.0.0", 9502, SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
$wservidor->set(
[
'ssl_cert_file' => 'ruta/certificado.pem',
'ssl_key_file' => '/ruta/privada/clave.key',
]
);
$wservidor->on('open', function (Swoole\WebSocket\Server $wservidor, $peticion) {
echo "servidor: handshake exitoso con fd{$peticion->fd}\n";
});
$wservidor->on('message', function (Swoole\WebSocket\Server $wservidor, $marco) {
echo "recibido desde {$marco->fd}:{$marco->datos},opcode:{$marco->opcode},fin:{$marco->fin}\n";
$wservidor->push($marco->fd, "respuesta del servidor");
});
$wservidor->on('close', function ($wservidor, $identificador) {
echo "cliente {$identificador} desconectado\n";
});
$wservidor->start();