问答 前端有时候收不到后端转发的 WebSocket 信息,不知道哪里出了问题,请各位大佬看一下

上官一 · 2025年01月16日 · 最后由 上官一 回复于 2025年01月16日 · 4317 次阅读

操作步骤:前端点击前台运行按钮,会调用 runcase 函数,请求/api/add_test_report 接口,获取 report_id,然后调用 initSocket 函数和运行 case 接口。后端会实时返回运行步骤。
遇到的问题:前端有时候能接受到后端 WebSocket 消息,有时候又接收不到
地址:https://www.shangguangroup.top/asynctest(需要先登录再访问) 账号:test 密码:123456
日志:

正常情况下是这样的:

有时候就就收不到后端转发的消息:

后端代码:
https://gitee.com/shangguanyi666/rd-testing-platform/blob/master/app.py
代码行数:
WebSocket 服务相关:41-91 525-546
https://gitee.com/shangguanyi666/rd-testing-platform/blob/master/playwright_method.py
代码行数:
向服务器发送消息:439-468
https://gitee.com/shangguanyi666/rd-testing-platform/blob/master/tests/test_01.py
代码行数:
调用发送新消息代码:47-52 158-166

前端代码
https://gitee.com/shangguanyi666/fe-uitest-platform/blob/main/src/components/asynctest.vue

代码行数:
运行 case 函数:957-1003
WebSocket :1346-1544

我在本地上运行时没问题的,本地运行命令:

服务器运行命令:nohup uvicorn app:app --host 0.0.0.0 --port 5004 --workers 4 > ./log/app.log 2>&1 &
nginx 服务器配置:

server {
    listen 80;
    server_name www.shangguangroup.top;

    # 将 HTTP 请求重定向到 HTTPS
    return 301 https://$host$request_uri;
}

server {
    # 监听 443 端口(HTTPS)并指定域名
    listen 443 ssl;
    server_name www.shangguangroup.top;

    # SSL 证书路径
    ssl_certificate /etc/letsencrypt/live/www.shangguangroup.top/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.shangguangroup.top/privkey.pem;

    # 启用 TLS 1.2 和 TLS 1.3,确保加密协议的安全性
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;  # 优先使用服务器端的加密套件

    # SSL 优化配置
    ssl_session_cache shared:SSL:10m;  # 共享 SSL 会话缓存,减少握手次数
    ssl_session_timeout 10m;          # SSL 会话缓存有效时间
    ssl_ciphers HIGH:!aNULL:!MD5;     # 禁用弱加密套件
    ssl_stapling on;                  # 启用 OCSP Stapling 提高握手效率
    ssl_stapling_verify on;           # 验证 OCSP Stapling 的响应
    resolver 8.8.8.8 8.8.4.4 valid=300s;  # 指定 DNS 解析器
    resolver_timeout 5s;                  # DNS 解析超时时间

    # 慢速客户端保护,避免长时间占用连接
    client_body_timeout 10s;   # 客户端发送请求体的超时时间
    client_header_timeout 10s;  # 客户端发送头部的超时时间
    keepalive_timeout 60s;     # 长连接保持时间

    # 配置前端静态资源目录
    location / {
        root /home/gitee/fe/fe-uitest-platform/dist;  # 前端项目的静态资源路径
        try_files $uri $uri/ /index.html;            # 前端路由支持 SPA 应用
    }

    # 配置后端 API 的反向代理
    location /api/ {
        proxy_pass http://127.0.0.1:5004;  # 代理到后端服务(Uvicorn 或 Gunicorn)
        proxy_http_version 1.1;            # 使用 HTTP 1.1,支持长连接
        proxy_set_header Host $host;       # 保留原始主机头
        proxy_set_header X-Real-IP $remote_addr;           # 传递客户端真实 IP
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  # 传递代理链
        proxy_set_header X-Forwarded-Proto $scheme;         # 传递请求协议(HTTP/HTTPS)

        # 设置超时时间,防止后端阻塞
        proxy_connect_timeout 60s;  # 连接后端超时
        proxy_read_timeout 600s;     # 读取后端响应超时,测试用例运行时间较长
        proxy_send_timeout 60s;     # 发送请求到后端超时

        # 配置缓冲,优化大响应数据
        proxy_buffer_size 4k;          # 单块缓冲区大小
        proxy_buffers 4 32k;           # 缓冲区数量和大小
        proxy_busy_buffers_size 64k;  # 忙缓冲区大小

    }
    # 配置 WebSocket 的反向代理
    location /api/ws/ {
        proxy_pass http://127.0.0.1:5004;  # 代理到后端服务
        proxy_http_version 1.1;            # 使用 HTTP 1.1,支持长连接
        proxy_set_header Upgrade $http_upgrade;  # 支持 WebSocket 升级
        proxy_set_header Connection "upgrade";   # 连接升级
        proxy_set_header Host $host;       # 保留原始主机头
        proxy_set_header X-Real-IP $remote_addr;           # 传递客户端真实 IP
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;  # 传递代理链
        proxy_set_header X-Forwarded-Proto $scheme;         # 传递请求协议(HTTP/HTTPS)

        # 设置超时时间,防止后端阻塞
        proxy_connect_timeout 60s;  # 连接后端超时
        proxy_read_timeout 600s;     # 读取后端响应超时
        proxy_send_timeout 60s;     # 发送请求到后端超时
    }   

    # 配置测试报告的静态文件路径
    location /ui-testreports/ {
        alias /home/ui-testreports/;  # 测试报告存放路径
        expires 30d;                 # 缓存时间设置为 30 天
        access_log off;              # 关闭日志记录,减少磁盘 I/O
    }
}

共收到 3 条回复 时间 点赞

本地运行是单进程所以没问题,多进程有问题

上官一 回复


多进程下 ws 连接的 app 实例,与你其他请求连接的 app 实例不是一个,但你都是在内存里存储的连接,而恰好进程资源是不共享的,你可以通过日志打印进程号验证这一点,多进程下你必须通过一个中间件共享资源。

Ayo 回复

感谢大佬 我用 redis 试了一下是可以的

上官一 关闭了讨论 01月17日 11:24
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册