Web服务器-Nginx代理WebSocket

63 阅读3分钟

作者介绍:简历上没有一个精通的运维工程师。请点击上方的蓝色《运维小路》关注我,下面的思维导图也是预计更新的内容和当前进度(不定时更新)。

我们上一大章介绍了Kubernetes的知识,本章节我们进入中间件的讲解,这里会包含很多不同的类型组件,中间件的第一个大类我这里定义的是Web服务器。由于目前使用最广泛的Web服务器是Nginx,所以我们这里的讲解主要以Nginx服务器为主。

今天我们来介绍一种特殊后端服务WebSocket,他的配置和普通网站代理很不一样。WebSocket 是一种在单个TCP连接上进行全双工通信的协议。它使得客户端和服务器之间的数据交换变得更加简单,允许服务器主动向客户端推送数据。正常我们请求普通网页,只有我们主动向服务器发起请求,服务端不能主动向我们推送请求。

1.构建一个WebSocket服务

定义主动推送数据给客户端,推送的当前时间,每10秒一次。

#安装pip命令
curl https://bootstrap.pypa.io/pip/2.7/get-pip.py -o get-pip.py
python get-pip.py
#安装依赖软件
yum -y install python-devel
#安装websocket支持 
pip install autobahn==0.10.4 twisted==15.5.0

#python的WebSocket服务 
# -*- coding: utf-8 -*-
import time
import random
import json  # 新增导入 json 模块
from twisted.internet import reactor
from autobahn.twisted.websocket import WebSocketServerFactory, WebSocketServerProtocol
import txaio

txaio.use_twisted()

class MyServerProtocol(WebSocketServerProtocol):
    def __init__(self):
        super(MyServerProtocol, self).__init__()
        self.task = None

    def onOpen(self):
        print(u"[服务端] 客户端连接成功")
        self.start_pushing()

    def start_pushing(self):
        def push():
            data = {
                u"time": u"当前时间: {}".format(time.strftime("%Y-%m-%d %H:%M:%S")),
                u"value": u"随机值: {:.2f}".format(random.random())
            }
            # 将数据转换为 JSON 字符串并编码为 UTF-8 字节
            json_data = json.dumps(data, ensure_ascii=False).encode('utf-8')
            self.sendMessage(json_data)
            self.task = reactor.callLater(10, push)
        self.task = reactor.callLater(0, push)

    def onClose(self, wasClean, code, reason):
        print(u"[服务端] 客户端断开连接")
        if self.task and self.task.active():
            self.task.cancel()

if __name__ == '__main__':
    factory = WebSocketServerFactory(u"ws://0.0.0.0:9000")
    factory.protocol = MyServerProtocol
    reactor.listenTCP(9000, factory)
    print(u"[服务端] 服务已启动,监听端口 9000")
    reactor.run()

前端代码,保存为xxx.html,然后使用浏览器打开,这个时候还没有引入Nginx代理,是浏览器直接访问WebSocket服务。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8"> <!-- 必须指定编码 -->
    <title>WebSocket 测试</title>
</head>
<body>
    <div id="output"></div>
    <script>
        var ws = new WebSocket('ws://192.168.31.121:9000');
        ws.onmessage = function(event) {
            var data = JSON.parse(event.data);  // 解析 JSON
            document.getElementById('output').innerHTML = 
                data.time + "<br>" + data.value;
        };
    </script>
</body>
</html>

#当前未使用代理的,直接访问WebSoket的情况 
当前时间: 2025-04-06 11:21:01随机值: 0.07
当前时间: 2025-04-06 11:21:11随机值: 0.11

2.使用Nginx代理WebSocket

location /ws {
    proxy_pass http://192.168.31.121:9000;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

proxy_http_version 1.1:强制使用 HTTP 1.1 协议与后端通信。

  • WebSocket 协议依赖 HTTP 1.1 的 Upgrade 机制完成握手。

  • Nginx 默认使用 HTTP 1.0 与后端通信,无法支持协议升级。

proxy_set_header Upgrade $http_upgrade:将客户端的 Upgrade 请求头透传给后端服务器。

  • $http_upgrade 变量捕获客户端请求中的 Upgrade 头(通常为 websocket)。
  • 后端服务器需通过 Upgrade: websocket 头识别 WebSocket 握手请求。

proxy_set_header Connection "upgrade":修改 Connection 请求头为 upgrade,指示后端启用协议升级。

  • Upgrade 头配合,告知后端需要将连接从 HTTP 升级为 WebSocket。

3.验证效果

静态网页的代码把地址修改为使用Nginx代理以后的地址。

这个最核心的就是访问的状态码变成101,如果未有这个则这个WebSocket访问就是失败的。如果你有共有云的机器,在使用控制台登录的时候,就会用到这个WebSocket,因为他们基本上都是通过WebSocket代理到虚拟机的vnc端口。

运维小路

一个不会开发的运维!一个要学开发的运维!一个学不会开发的运维!欢迎大家骚扰的运维!

关注微信公众号《运维小路》获取更多内容。