nginx反向代理WebSocket

WebSocket协议相比较于HTTP协议成功握手后能够屡次进行通信,直到链接被关闭。可是WebSocket中的握手和HTTP中的握手兼容, 它使用HTTP中的Upgrade协议头将链接从HTTP升级到WebSocket。这使得WebSocket程序能够更容易的使用现已存在的基础设施。javascript

WebSocket工做在HTTP的80和443端口并使用前缀ws://或者wss://进行协议标注,在创建链接时使用HTTP/1.1的101状态码进行协议切换, 当前标准不支持两个客户端之间不借助HTTP直接创建Websocket链接。html

更多Websocket的介绍可参考我写的 聊一聊WebSocket 一文。java

开发小程序的时候须要用到WebSocket长链接和推送技术,可是必须使用wss,而且必须经过域名访问。这时候就须要用到nginx反向代理了。nginx

原理 通常咱们开发的WebSocket服务程序使用ws协议,明文的。可是怎样让它安全的经过互联网传输呢?这时候能够经过nginx在客户端和服务端直接作一个转发了, 客户端经过wss访问,而后nginx和服务端经过ws协议通讯。web

以下图所示:小程序

配置 前提条件是你有一个域名,而且申请好了证书。浏览器

nginx版本: 1.12 nginx相关配置内容以下:安全

map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

upstream websocket {
    server localhost:port; # 这里port改为你的websocket端口
}

server {
     server_name xxx.com;
     listen 443 ssl;
     location / {
         proxy_pass http://websocket;
         proxy_read_timeout 300s;
         proxy_send_timeout 300s;
         
         proxy_set_header Host $host;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         
         proxy_http_version 1.1;
         proxy_set_header Upgrade $http_upgrade;
         proxy_set_header Connection $connection_upgrade;
     }
    ssl_certificate /etc/letsencrypt/live/test.enzhico.net/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/test.enzhico.net/privkey.pem;
}
复制代码

之类解释一下关键配置部分:bash

最重要的就是在反向代理的配置中增长了以下两行,其它的部分和普通的HTTP反向代理没有任何差异。服务器

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
复制代码

这里面的关键部分在于HTTP的请求中多了以下头部:

Upgrade: websocket
Connection: Upgrade
复制代码

这两个字段表示请求服务器升级协议为WebSocket。服务器处理完请求后,响应以下报文:

# 状态码为101
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: upgrade
复制代码

告诉客户端已成功切换协议,升级为Websocket协议。握手成功以后,服务器端和客户端便角色对等,就像普通的Socket同样,可以双向通讯。 再也不进行HTTP的交互,而是开始WebSocket的数据帧协议实现数据交换。

这里使用map指令能够将变量组合成为新的变量,会根据客户端传来的链接中是否带有Upgrade头来决定是否给源站传递Connection头, 这样作的方法比直接所有传递upgrade更加优雅。

默认状况下,链接将会在无数据传输60秒后关闭,proxy_read_timeout参数能够延长这个时间。源站经过按期发送ping帧以保持链接并确认链接是否还在使用。

两个超时参数

proxy_read_timeout

语法 proxy_read_timeout time 默认值 60s 上下文 http server location 说明 该指令设置与代理服务器的读超时时间。它决定了nginx会等待多长时间来得到请求的响应。 这个时间不是得到整个response的时间,而是两次reading操做的时间。

proxy_send_timeout

语法 proxy_send_timeout time 默认值 60s 上下文 http server location 说明 这个指定设置了发送请求给upstream服务器的超时时间。超时设置不是为了整个发送期间,而是在两次write操做期间。 若是超时后,upstream没有收到新的数据,nginx会关闭链接

屡次代理转发

工做中碰见过一种状况,就是某个域名在移动网络下面访问不了,这样的话我须要经过一个前段代理服务器作转发,这样就涉及到两次代理。

好比访问的websocket服务URL为:

wss://xxx.com
复制代码

只须要最外层使用wss协议,里面的交互都使用ws协议,因此监听80端口便可。

浏览器调试以下:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title></title>
    <script type="text/javascript">
        ws = new WebSocket("wss://xxx.com");
        ws.onopen = function() {
            alert("链接成功");
            ws.send('tom');
            alert("给服务端发送一个字符串:tom");
        };
        ws.onmessage = function(e) {
            alert("收到服务端的消息:" + e.data);
        };
    </script>
</head>

<body>
</body>

</html>

复制代码

参考链接

相关文章
相关标签/搜索