【无标题】

一、文档说明

本文档基于当前 SPC 工业平台完整 Docker 微服务架构编写,适用于项目统一入口 Nginx 反向代理网关。

覆盖内容:Nginx 容器架构说明、目录结构、完整配置、启停重载、配置更新、故障排查、子路径代理、WebSocket 转发、API 网关转发、生产运维规范。

适配架构:Docker Compose + 双网络(public-net 外网访问、internal-net 服务内网)

二、Nginx 网关架构概述

1. 核心定位

Nginx 作为项目统一流量入口,承载所有前端页面、后端 API、WebSocket 长连接的反向代理,统一对外暴露 80/443 端口,实现动静分离、路由分发、路径重写、跨域代理。

2. 网络模式说明

  • public-net(桥接外网):Nginx、前端服务、网关服务暴露外网可访问端口

  • internal-net(私有内网):所有后端微服务内网互通,不对外暴露,保障服务安全

3. 代理业务清单

  • 主前端 SPC.Web:根路径 / 与子路径 /spc-web/ 双访问适配

  • 3D 可视化前端 SPC.3D:子路径 /spc-3d/ 访问

  • WebSocket 实时长连接:/ws/ 路由转发至 API 网关

  • 全局 API 接口:/api/ 统一转发至网关服务 55000 端口

三、Nginx 部署目录结构

部署根目录:与 docker-compose.yml 同级

复制代码
./proxy
├── nginx
│   └── conf.d/         # 站点配置目录(所有代理规则存放处)
│       └── default.conf # 核心代理配置文件
└── ssl/                # HTTPS 证书存放目录

ocker中网关必须有如下内容:

bash 复制代码
// WS路由:精确匹配 /ws/xxx 高优先级
        {
            "DownstreamPathTemplate": "/{everything}",
            "DownstreamScheme": "ws",
            "DownstreamHostAndPorts": [
                {
                    "Host": "spcoverviewservice",
                    "Port": 9019
                }
            ],
            "UpstreamPathTemplate": "/ws/{everything}",
            "UpstreamHttpMethod": [ "GET" ],
            "Priority": 10
        },
        // WS兜底:纯/ws 根路径
        {
            "DownstreamPathTemplate": "/",
            "DownstreamScheme": "ws",
            "DownstreamHostAndPorts": [
                {
                    "Host": "spcoverviewservice",
                    "Port": 9019
                }
            ],
            "UpstreamPathTemplate": "/ws/",
            "UpstreamHttpMethod": [ "GET" ],
            "Priority": 5
        }

四、Docker Compose Nginx 服务配置

以下为项目生产可用 Nginx 完整服务配置,集成日志、时区、挂载、依赖、网络策略。

bash 复制代码
version: "3.8"

networks:
  public-net:
    driver: bridge
  internal-net:
    external: true

services:
  # 统一入口Nginx网关
  proxy:
    image: 10.31.20.10:8081/build-tools/nginx:1.25
    container_name: spc-proxy
    restart: always
    ports:
      - "56000:80"
      - "443:443"
    volumes:
      - ./proxy/nginx/conf.d:/etc/nginx/conf.d
      - ./proxy/ssl:/etc/nginx/ssl
    environment:
      - TZ=Asia/Shanghai
    networks:
      - public-net
    depends_on:
      - spc-web
      - spc-3d
      - spcwebgateway

  # 主前端应用
  spc-web:
    image: 10.31.20.10:8081/sensesmill-docker/spc.web:beta
    container_name: spc-web
    restart: always
    expose:
      - "80"
    volumes:
      - ./web/spc.web/app-config/app-config.prod.json:/usr/share/nginx/html/assets/file/app-config/app-config.prod.json
    environment:
      - TZ=Asia/Shanghai
    networks:
      - public-net

  # 3D可视化前端
  spc-3d:
    image: 10.31.20.10:8081/sensesmill-docker/spc.3d:beta
    container_name: spc-3d
    restart: always
    expose:
      - "80"
    volumes:
      - ./web/spc.3d/app-config/config.json:/usr/share/nginx/html/config/config.json
      - ./web/spc.3d/app-config/dataConfig.json:/usr/share/nginx/html/config/dataConfig.json
    environment:
      - TZ=Asia/Shanghai
    networks:
      - public-net

  # API网关服务
  spcwebgateway:
    image: 10.31.20.10:8081/sensesmill-docker/spcwebgateway:beta
    container_name: spcwebgateway
    restart: always
    ports:
      - "55000:80"
      - "55443:443"
    volumes:
      - ./spcwebgateway/Logs:/app/Logs
      - ./spcwebgateway/config/appsettings.json:/app/appsettings.json
      - ./spcwebgateway/config/ocelot.json:/app/ocelot.json
    environment:
      - TZ=Asia/Shanghai
      - ASPNETCORE_URLS=http://+:80
    logging:
      driver: json-file
      options:
        max-size: 10m
        max-file: "31"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80/Health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    networks:
      - public-net
      - internal-net

  # 认证授权中心
  spcplantdataservice-authserver:
    image: 10.31.20.10:8081/sensesmill-docker/spcplantdataservice-authserver:beta
    container_name: spcplantdataservice-authserver
    restart: always
    ports:
      - "55001:80"
    volumes:
      - ./spcplantdataservice-authserver/Logs:/app/Logs
      - ./spcplantdataservice-authserver/config/appsettings.json:/app/appsettings.json
    environment:
      - TZ=Asia/Shanghai
      - ASPNETCORE_URLS=http://+:80
    logging:
      driver: json-file
      options:
        max-size: 10m
        max-file: "31"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80/Health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    networks:
      - public-net
      - internal-net

  # 工厂基础数据服务
  spcplantdataservice:
    image: 10.31.20.10:8081/sensesmill-docker/spcplantdataservice:beta
    container_name: spcplantdataservice
    restart: always
    ports:
      - "55002:80"
    volumes:
      - ./spcplantdataservice/Logs:/app/Logs
      - ./spcplantdataservice/config/appsettings.json:/app/appsettings.json
      - ./spcplantdataservice/BlobStoreFiles:/app/BlobStoreFiles
      - ./spcplantdataservice/file:/app/file
    environment:
      - TZ=Asia/Shanghai
      - ASPNETCORE_URLS=http://+:80
    logging:
      driver: json-file
      options:
        max-size: 10m
        max-file: "31"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80/Health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    networks:
      - public-net
      - internal-net

配置说明

  • 镜像:私有仓库 Nginx1.25 稳定版

  • 端口映射:外网 56000 映射容器80,443 用于HTTPS

  • 配置挂载:本地 conf.d 目录挂载容器配置目录,支持热更新

  • 证书挂载:统一存放 SSL 证书文件

  • 依赖启动:优先等待前端、网关服务启动后再启动 Nginx

  • 网络隔离:仅接入外网网络,不直接接入内网服务网络,提升安全性

五、Nginx 核心代理配置(default.conf)

适配项目子路径访问、静态资源重写、WebSocket、API转发完整配置,可直接覆盖使用。

复制代码
server {
    listen 80;
    server_name _;

    # SPC.Web - 根路径(保持原样)
    location / {
        proxy_pass http://spc-web:80;
        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_set_header X-Forwarded-Proto $scheme;
    }

    # SPC.Web - 子路径访问(新增)
    location /spc-web/ {
        proxy_pass http://spc-web:80/;
        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_set_header X-Forwarded-Proto $scheme;
        
        # 替换 HTML 中的路径前缀(如果 spc-web 使用根路径引用资源)
        sub_filter '<base href="/">' '<base href="/spc-web/">';
        sub_filter 'src="/' 'src="/spc-web/';
        sub_filter 'href="/' 'href="/spc-web/';
        sub_filter_once off;
    }

    # SPC.3D - 子路径访问
    location /spc-3d/ {
        proxy_pass http://spc-3d:80/;
        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_set_header X-Forwarded-Proto $scheme;
        
        sub_filter '<base href="/">' '<base href="/spc-3d/">';
        sub_filter 'src="/' 'src="/spc-3d/';
        sub_filter 'href="/' 'href="/spc-3d/';
        sub_filter_once off;
    }
    
     # WebSocket
    location /ws/ {
        proxy_pass http://spcwebgateway:80;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_read_timeout 3600s;
    }

    # API
    location /api/ {
        proxy_pass http://spcwebgateway:80;
        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_set_header X-Forwarded-Proto $scheme;
        proxy_connect_timeout 120s;
        proxy_read_timeout 120s;
    }
}

或者直接挂载nginx.conf

bash 复制代码
# ------------------------
# Docker容器内Nginx 80端口网关主机配置
# 作用:统一入口反向代理内部各业务容器(spc-web/spc-3d/spcwebgateway)
# 容器网络内可直接通过容器名作为域名通信,无需宿主机IP
# ------------------------
server {
    # 容器内监听80端口,对外由docker端口映射暴露访问
    listen 80;
    # 匹配所有访问域名,不限制前端访问域名
    server_name _;

    # ======================================
    # 1. SPC.Web前端容器 - 根路径访问
    # 外部访问地址:http://宿主机IP/
    # 转发目标:同Docker网络内 spc-web 容器80端口
    # proxy_pass 末尾无斜杠:完整保留客户端原始请求路径转发给前端容器
    # ======================================
    location / {
        proxy_pass http://spc-web:80;
        # 透传客户端原始访问域名,前端/后端可获取真实Host
        proxy_set_header Host $host;
        # 传递客户端真实公网IP(宿主机转发场景日志溯源用)
        proxy_set_header X-Real-IP $remote_addr;
        # 多级代理链路完整IP记录
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        # 透传当前访问协议 http/https,适配鉴权、跳转逻辑
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # ======================================
    # 2. SPC.Web前端容器 - 子路径 /spc-web/ 访问
    # 外部访问地址:http://宿主机IP/spc-web/
    # 场景:前端打包仅适配根路径 "/",无法重新打包,用sub_filter动态替换HTML内资源路径
    # Docker容器代理必须双关闭压缩:gzip off + 清空Accept-Encoding,防止上游容器返回压缩HTML导致替换失效
    # proxy_pass末尾带/:自动截断URL前缀/spc-web/,转发给spc-web容器根路径
    # ======================================
    location /spc-web/ {
        proxy_pass http://spc-web:80/;
        # 透传客户端请求基础信息头
        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_set_header X-Forwarded-Proto $scheme;

        # 【Docker代理关键配置】局部关闭当前location的gzip压缩
        gzip off;
        # 清空Accept-Encoding请求头,告知上游spc-web容器不要返回gzip压缩包,保证HTML明文输出
        proxy_set_header Accept-Encoding "";

        # 替换页面基础路由基准标签,所有资源/路由以 /spc-web/ 为根
        sub_filter '<base href="/">' '<base href="/spc-web/">';
        # 替换JS/CSS/图片静态资源绝对路径,避免404
        sub_filter 'src="/' 'src="/spc-web/';
        # 替换页面内a标签跳转链接,防止路由丢失子路径前缀
        sub_filter 'href="/' 'href="/spc-web/';
        # sub_filter_once off:页面内所有匹配文本全部替换,不止替换第一个
        sub_filter_once off;
    }

    # ======================================
    # 3. SPC.3D可视化前端容器 - 子路径 /spc-3d/ 访问
    # 外部访问地址:http://宿主机IP/spc-3d/
    # 逻辑同/spc-web/,适配子目录部署,关闭压缩保障HTML字符串替换生效
    # 转发目标:Docker内网 spc-3d 容器80端口
    # ======================================
    location /spc-3d/ {
        proxy_pass http://spc-3d:80/;
        # 透传客户端请求头
        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_set_header X-Forwarded-Proto $scheme;

        # 【Docker代理关键配置】关闭压缩,获取明文HTML用于路径替换
        gzip off;
        proxy_set_header Accept-Encoding "";

        # 替换3D页面全部根路径引用,适配/spc-3d/子目录访问
        sub_filter '<base href="/">' '<base href="/spc-3d/">';
        sub_filter 'src="/' 'src="/spc-3d/';
        sub_filter 'href="/' 'href="/spc-3d/';
        sub_filter_once off;
    }

    # ======================================
    # 4. WebSocket长连接代理 /ws/
    # 转发目标:网关容器 spcwebgateway:80
    # 业务场景:实时数据推送、设备监控、在线消息、3D实时联动
    # Docker容器间WebSocket必须开启HTTP/1.1、协议升级、延长读写超时
    # ======================================
    location /ws/ {
        proxy_pass http://spcwebgateway:80;
        # WebSocket协议升级强制依赖HTTP/1.1,HTTP1.0不支持
        proxy_http_version 1.1;
        # 标记协议升级:HTTP 切换 WebSocket
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        # 长连接空闲超时1小时,避免容器间ws连接被nginx主动断开
        proxy_read_timeout 3600s;
    }

    # ======================================
    # 5. 后端API接口统一代理 /api/
    # 所有业务接口统一转发至网关容器 spcwebgateway:80
    # 延长超时时间,适配大数据导出、报表慢查询、复杂生产计算接口
    # ======================================
    location /api/ {
        proxy_pass http://spcwebgateway:80;
        # 透传客户端真实IP、访问协议,后端鉴权/审计日志使用
        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_set_header X-Forwarded-Proto $scheme;
        # 与网关容器建立连接的超时时间
        proxy_connect_timeout 120s;
        # 接口响应读取超时,适配耗时业务接口
        proxy_read_timeout 120s;
    }
}

六、核心功能详解

1. 子路径适配原理

前端项目默认根路径打包,直接子路径访问会出现静态资源404。通过sub_filter 动态替换 html 内的 base、src、href 路径,实现无需改前端代码,Nginx 层自动适配子路径。

2. WebSocket 长连接支持

开启 HTTP1.1、Upgrade 升级头、超长读取超时(1小时),适配设备实时数据、报警推送、3D 实时联动场景,杜绝长连接断开问题。

3. API 统一转发

所有前端 /api/ 请求统一转发至后端网关服务 55000 端口,由 Ocelot 网关统一路由到各个微服务(设备、能耗、报警、生产、质量、时序数据服务)。

七、日常运维操作命令

所有命令在docker-compose.yml 同级目录执行

1. 启动 Nginx

复制代码
docker compose up -d proxy

2. 停止 Nginx

复制代码
docker compose down proxy

3. 重启 Nginx

复制代码
docker compose restart proxy

4. 配置热重载(重要,不重启容器生效)

修改 nginx 配置后,必须执行重载,避免重启服务断流

复制代码
# 检查配置语法
docker exec -it spc-proxy nginx -t

# 热重载配置
docker exec -it spc-proxy nginx -s reload

5. 查看 Nginx 日志

复制代码
# 实时日志
docker logs -f spc-proxy

6. 进入容器内部调试

复制代码
docker exec -it spc-proxy bash

八、常见故障排查方案

1. 子路径访问页面空白、静态资源404

原因:sub_filter 规则未生效或配置未重载

解决:检查配置文件、执行 nginx -t && nginx -s reload

2. WebSocket 连接失败、频繁断开

原因:未开启升级头、超时时间过短

解决:确认 location /ws/ 配置完整,超时时间不低于 3600s

3. API 接口 502/504 超时

原因:代理超时时间不足、网关服务未启动

解决:调整 proxy 超时参数,检查 spcwebgateway 健康状态

4. Nginx 启动失败

排查步骤:

  1. 检查配置语法:docker exec spc-proxy nginx -t

  2. 检查端口占用:80/443/56000

  3. 检查挂载目录权限

九、生产运维规范

  • 所有 Nginx 配置修改必须先检查语法再重载,禁止直接重启容器

  • 前端新增子页面、新服务路由,统一在 conf.d 中新增 location 规则

  • SSL 证书过期前提前替换,存放至 ./proxy/ssl 目录

  • 严禁直接修改容器内配置,所有配置通过本地挂载文件管理

  • 对外端口统一由 Nginx 暴露,后端微服务禁止直接对外开放端口

十、附录:项目完整代理路由对照表

|-----------|------------------|---------------|
| 访问路径 | 代理目标服务 | 用途 |
| / | spc-web:80 | 主系统首页 |
| /spc-web/ | spc-web:80 | 主系统子路径访问 |
| /spc-3d/ | spc-3d:80 | 3D可视化页面 |
| /ws/ | spcwebgateway:80 | 实时WebSocket推送 |
| /api/ | spcwebgateway:80 | 所有后端微服务接口 |