websocket的应用

实时推送消息,减少网络流量,实质是一个tcp的长连接. 一般本地开发,不是http的协议,所以使用的websocket是以ws://协议形式的. 当放到生产,若开启了https,则应该是以wss://形式的协议. 但是仅仅更改这个协议头是不行的.错误的websocket地址可能会导致如下报错: WebSocket connection to ‘wss://example.com:8088/websocket’ failed: Error in connection establishment: net::ERR_SSL_PROTOCOL_ERROR

主要原因

  1. ws 基于http下的一种协议,默认的服务端口是80.
  2. wss 基于https下的一种协议,默认的服务端口是433,如果使用wss则也需要使用433的端口号而不是80,因为我们的SSL证书配置的都是针对433端口的. 这个才是原因所在.

如何挖的坑

  1. 本地开发,一般都是使用的http于是前端这样写:
    var myWebSocket,webSocketUrl='ws://localhost:8080/websocket'
    if ('WebSocket' in window) {
     myWebSocket = new WebSocket(webSocketChenkunUrl);
    } else if ('MozWebSocket' in window) {
     myWebSocket = new MozWebSocket(webSocketChenkunUrl);
    } else {
     alert( 'not support');
    }
    
  2. 部署到服务器上,因为地址跟端口不固定,于是自作聪明通过一个请求从服务端返回webSocketUrl:
    ...
    @RequestMapping("/ws/getServer")
    public Result<String> getServer(HttpServletRequest request) {
     String serverEndPoint = "/websocket";
     String server = String.format("ws://%s:%s%s", request.getServerName(), request.getServerPort(), serverEndPoint);
     LOGGER.debug("get ws server,return:{}", server);
     return new Result<>(server);
    }
    ...
    
  3. 服务器使用https 为了兼容本地与服务端,针对request.getScheme()判断请求是http还是https,判断失败,原因是通过了nginx反向代理指向的是服务器地址,所有请求在服务端的感知下都是http的. 使用其他header进行判定,进而在生产上返回wss://的协议地址. 测试报错如下: WebSocket connection to ‘wss://example.com:80/websocket’ failed: Error in connection establishment: net::ERR_SSL_PROTOCOL_ERROR
  4. 解决: 因为https协议是在433端口,所以wss://协议的地址也应该是433.