Files
BuYuHouDuan/docs/06-网关模块-Gateway.md
T
2026-10-12 16:22:04 +08:00

16 KiB
Raw Blame History

网关模块(Gateway)—— 功能与代码目录文档

本文档是「网关模块(Gateway)」的完整上下文说明文档,用于把该模块的背景、职责、路由规则、项目结构、目录树与关键文件一次性提供给其他对话或开发者,使其无需阅读源码即可准确理解该模块。文中所有内容均以 d:\BUYUHouDuanNet\BuYu\Gateway\ 下的实际代码与配置为准。

一、平台背景与模块位置

本模块所属项目为「捕鱼 + 棋牌游戏运营平台」后端,位于解决方案 Template0524.sln(根目录 d:\BUYUHouDuanNet\BuYu\)中的 Gateway\Gateway.csproj。

平台整体技术栈:

  • 运行时 / 框架:.NET 8(各工程目标框架均为 net8.0)
  • 数据库:MongoDB
  • 缓存:Redis
  • 消息队列:RabbitMQ(通过 CAP / DotNetCore.CAP 使用,对应基础设施工程 RabbitMQHelper)
  • 实时通信:SignalR
  • API 网关:Ocelot
  • 日志:NLog
  • IoC 容器:Autofac

平台由多个后端宿主(Host)服务 + 一个网关组成。各后端服务及其监听端口(与 Gateway\ocelot.json 的下游端口逐一对应):

后端服务 说明 端口
AdminHost 后台管理端宿主 5241
UserHost 用户端宿主 5245
CustomerHost 客服端宿主 5247
ChessGameHost 棋牌游戏宿主 5242
FishRoomHost 捕鱼房间宿主 5244
FishGameHost 捕鱼游戏宿主 5248

网关自身的对外入口(BaseUrl / 监听端口)为 http://localhost:8001(由 ocelot.json 的 GlobalConfiguration.BaseUrl 与 appsettings.json 的 urls 共同确定)。

模块位置:在解决方案中,Gateway 作为独立顶层工程存在,工程 GUID 为 {430C217C-897A-42EE-996D-75A02FF22A50},物理路径为 Gateway\。它是所有前端请求进入后端的唯一统一入口。

二、模块简介

网关模块基于 Ocelot 20.0.0 实现,是整个平台的统一流量入口。其定位与职责如下:

  1. 统一入口:前端(用户端、客服端、后台管理端、游戏端)只需访问网关地址 http://localhost:8001,无需关心后端各服务的真实地址与端口。
  2. 路由转发:依据 ocelot.json 中声明式的 Routes 配置,把上游(Upstream)请求按路径模板转发到对应下游(Downstream)服务。
  3. 反向代理与转发头处理:通过 ForwardedHeaders 中间件处理 X-Forwarded-For / X-Forwarded-Proto,保证后端服务能拿到真实客户端 IP 与协议(配置了可信代理白名单)。
  4. 健康检查:暴露 /health 健康检查端点。
  5. WebSocket / SignalR 透传:Ocelot 原生支持 WebSocket,网关同时承载各服务的 SignalR Hub 路径(见第三节)。
  6. 可扩展的横切能力(已注册但当前未按路由启用):
    • 已引入并注册 缓存(Ocelot.Cache.CacheManager,使用内存字典句柄);
    • 已引入并注册 Polly(Ocelot.Provider.Polly),具备按路由配置超时 / 重试 / 熔断的能力;
    • csproj 中引用了 AspNetCoreRateLimit 5.0.0,但 Program.cs 中未对其做任何注册或中间件装配。

当前网关不承担鉴权职责:ocelot.json 的所有路由均未配置 AuthenticationOptions / AuthenticationProviderKey,网关层不做 JWT / 身份校验,鉴权由各下游服务自行完成。

当前网关未配置 CORS:无论 Program.cs 还是 ocelot.json,都没有 CORS / SecurityOptions 相关配置,跨域由下游服务或前端处理。

三、路由清单

以下路由表完整对应 Gateway\ocelot.json 中 Routes 数组的 9 条路由(顺序与文件中一致)。所有路由的 DownstreamScheme 均为 http,UpstreamHttpMethod 均为 ["Get","POST","PUT","DELETE","OPTIONS"]。

上游路径模板(Upstream) 下游服务 下游地址 下游路径模板(Downstream) 用途说明
/loginhub/{everything} UserHost http://localhost:5245 /loginhub/{everything} 用户端登录相关 SignalR Hub
/customerHub/{everything} CustomerHost http://localhost:5247 /customerHub/{everything} 客服端 SignalR Hub
/chessgamehub/{everything} ChessGameHost http://localhost:5242 /chessgamehub/{everything} 棋牌游戏 SignalR Hub
/fishingroomhub/{everything} FishRoomHost http://localhost:5244 /fishingroomhub/{everything} 捕鱼房间 SignalR Hub
/gamehub/{everything} FishGameHost http://localhost:5248 /fishinghub/{everything} 捕鱼游戏 SignalR Hub(上游 /gamehub 映射到下游 /fishinghub,路径被重写)
/chess/{everything} ChessGameHost http://localhost:5242 /chess/{everything} 棋牌游戏 HTTP 接口
/adminapi/{everything} AdminHost http://localhost:5241 /adminapi/{everything} 后台管理 HTTP 接口
/api/{everything} UserHost http://localhost:5245 /api/{everything} 用户端 HTTP 接口
/customerapi/{everything} CustomerHost http://localhost:5247 /customerapi/{everything} 客服端 HTTP 接口

关于 SignalR / WebSocket 路由

以下 5 条属于 SignalR Hub(实时通信)路由,客户端通过 WebSocket 长连接访问,网关借助 Ocelot 的 WebSocket 透传能力转发:

  • /loginhub/*(→ UserHost:5245)
  • /customerHub/*(→ CustomerHost:5247)
  • /chessgamehub/*(→ ChessGameHost:5242)
  • /fishingroomhub/*(→ FishRoomHost:5244)
  • /gamehub/*(→ FishGameHost:5248,下游实际路径为 /fishinghub/*)

其余 4 条为常规 HTTP 接口路由:/chess/*、/adminapi/*、/api/*、/customerapi/*。

关键注意点(易错):除 /gamehub 外,其余路由的上游路径与下游路径同名;仅 /gamehub/{everything} 这一条被显式重写为下游 /fishinghub/{everything}。排查「游戏 Hub 连不上」类问题时需特别注意这一映射差异。

四、项目结构与技术要点

4.1 工程文件(Gateway.csproj)

  • 工程类型:Microsoft.NET.Sdk.Web

  • 目标框架:net8.0

  • 语言特性:Nullable=enable、ImplicitUsings=enable

  • 关键 NuGet 包:

    包名 版本 作用
    Ocelot 20.0.0 API 网关核心
    Ocelot.Cache.CacheManager 20.0.0 Ocelot 输出缓存扩展
    Ocelot.Provider.Polly 20.0.0 Ocelot 的 Polly 集成(QoS:超时/重试/熔断)
    AspNetCoreRateLimit 5.0.0 限流库(已在 csproj 引用,但代码中未启用)
  • 内容拷贝设置:

    • appsettings.json → CopyToOutputDirectory=Always
    • ocelot.json → CopyToOutputDirectory=Always(同时在 <None> 中声明为 PreserveNewest)
    • docker-compose.yaml → CopyToOutputDirectory=Always
    • Dockerfile → CopyToOutputDirectory=Always(注意:csproj 中引用了 Dockerfile,但当前工程目录下实际不存在该文件)

4.2 启动流程(Program.cs)要点

入口为顶层语句(Top-level statements),核心逻辑:

  1. 配置加载:
    • builder.Configuration.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true) —— ocelot.json 为必需文件,且支持热重载(修改路由配置无需重启)。
    • builder.Configuration.AddJsonFile(Path.Combine("Config", "system.json"), optional: true) —— Config\system.json 为可选补充配置。
  2. 注册 Ocelot:builder.Services.AddOcelot(builder.Configuration).AddCacheManager(x => x.WithDictionaryHandle()).AddPolly()
    • 使用内存字典(WithDictionaryHandle)作为缓存存储;
    • 启用 Polly 提供者(具备 QoS 能力,但路由中未配置 QoSOptions)。
  3. 健康检查:builder.Services.AddHealthChecks()。
  4. 转发头配置:Configure<ForwardedHeadersOptions> 设置 XForwardedFor | XForwardedProto,清空默认已知代理/网络后,加入可信代理 127.0.0.1、::1(IPv6)、172.19.0.1(其中 172.17.0.1、172.18.0.1 被注释掉)。
  5. 中间件管道:
    • app.UseForwardedHeaders() —— 启用转发头处理;
    • app.MapHealthChecks("/health") —— 暴露 /health;
    • await app.UseOcelot() —— 启用 Ocelot 网关(置于管道末尾,所有未匹配的路由交给 Ocelot 处理);
    • app.Run()。

4.3 配置文件加载方式

文件 是否必需 热重载 说明
ocelot.json 必需(optional:false) 是 网关路由与全局配置的唯一来源
Config\system.json 可选(optional:true) 否 补充配置(日志、Redis 连接等),合并进 IConfiguration

appsettings.json 与 Config\system.json 中都声明了 "Ocelot": { "Config": "ocelot.json" } 与 AllowedHosts;appsettings.json 额外声明了 Web 监听地址。

4.4 监听端口

  • appsettings.json 中 "urls": "http://*:8001" —— 网关对外监听 8001 端口(监听所有网卡的 8001)。
  • ocelot.json 中 GlobalConfiguration.BaseUrl = "http://localhost:8001",与之一致。
  • Properties\launchSettings.json(仅用于本机 Visual Studio 调试)中 applicationUrl 为 https://localhost:28831;http://localhost:28832,ASPNETCORE_ENVIRONMENT=Development。该调试端口与实际运行端口 8001 不同,是容易混淆之处。

4.5 部署方式

  • Docker Compose:docker-compose.yaml 定义了单个服务:
    • name: webapi(compose 项目名)
    • 服务名 0524gateway,容器名 0524gateway,镜像 0524gateway
    • restart: always
    • 端口映射 8001:80(宿主 8001 → 容器 80,容器内监听 80 端口)
  • 本机直接运行:dotnet run(读取 appsettings.json 的 urls = http://*:8001)。

五、代码目录说明

以下目录树覆盖 Gateway\ 下的全部文件夹与文件(已排除编译产物 bin/obj,该目录下当前未包含 bin/obj)。

Gateway/                              # 网关模块根目录(Ocelot API 网关工程)
├── Config/                           # 补充配置目录
│   └── system.json                   # 系统补充配置:日志级别、Ocelot 配置文件名、AllowedHosts、RedisConfig(连接串等)
├── Properties/                       # 工程属性目录(VS 调试用)
│   └── launchSettings.json           # 本机启动配置:Development 环境、调试用 applicationUrl(28831/28832)
├── appsettings.json                  # 应用主配置:监听地址 urls=http://*:8001、日志级别、AllowedHosts、Ocelot.Config
├── docker-compose.yaml               # Docker 部署编排:服务 0524gateway,端口映射 8001:80,restart=always
├── Gateway.csproj                    # 工程文件:net8.0 + Ocelot 20.0.0 等 NuGet 包引用、内容文件拷贝规则
├── ocelot.json                       # Ocelot 核心配置:9 条路由 Routes + GlobalConfiguration(BaseUrl=http://localhost:8001)
└── Program.cs                        # 程序入口:加载配置、注册 Ocelot/健康检查、转发头、UseOcelot 管道

说明:Gateway.csproj 中引用了 Dockerfile(<None Update="Dockerfile">),但该文件当前并未存在于 Gateway\ 目录中;docker-compose.yaml 引用的镜像 0524gateway 需由外部构建提供。

六、关键文件索引

文件相对路径 职责
Gateway/Gateway.csproj 工程定义:目标框架 net8.0,依赖 Ocelot 20.0.0 系列包与 AspNetCoreRateLimit 5.0.0,声明配置文件拷贝规则
Gateway/Program.cs 程序入口:加载 ocelot.json/Config/system.json,注册 Ocelot + CacheManager + Polly、健康检查、转发头,挂载 UseOcelot
Gateway/ocelot.json 网关路由与全局配置(9 条路由、下游服务/端口、/gamehub→/fishinghub 重写、BaseUrl=8001)
Gateway/appsettings.json 主配置:监听地址 http://*:8001、日志级别、AllowedHosts、Ocelot:Config=ocelot.json
Gateway/Config/system.json 补充配置:日志级别、Ocelot 配置项、AllowedHosts、RedisConfig(Host/Port/Password/Database/ConnectionString)
Gateway/Properties/launchSettings.json 本机 VS 调试配置:环境变量 ASPNETCORE_ENVIRONMENT=Development,调试 applicationUrl(28831/28832)
Gateway/docker-compose.yaml 容器化部署:单服务 0524gateway,镜像 0524gateway,端口 8001:80,restart: always

七、与其他模块的交互

网关是本平台前后端交互的唯一通道,其与各后端服务的交互完全由 ocelot.json 的路由映射决定。汇总如下(同时包含上游路径与下游目标):

7.1 网关到各服务的路由映射总表

上游路径模板 下游服务(端口) 下游地址 下游路径 类型
/loginhub/{everything} UserHost (5245) http://localhost:5245 /loginhub/{everything} SignalR Hub
/customerHub/{everything} CustomerHost (5247) http://localhost:5247 /customerHub/{everything} SignalR Hub
/chessgamehub/{everything} ChessGameHost (5242) http://localhost:5242 /chessgamehub/{everything} SignalR Hub
/fishingroomhub/{everything} FishRoomHost (5244) http://localhost:5244 /fishingroomhub/{everything} SignalR Hub
/gamehub/{everything} FishGameHost (5248) http://localhost:5248 /fishinghub/{everything}(重写) SignalR Hub
/chess/{everything} ChessGameHost (5242) http://localhost:5242 /chess/{everything} HTTP API
/adminapi/{everything} AdminHost (5241) http://localhost:5241 /adminapi/{everything} HTTP API
/api/{everything} UserHost (5245) http://localhost:5245 /api/{everything} HTTP API
/customerapi/{everything} CustomerHost (5247) http://localhost:5247 /customerapi/{everything} HTTP API

按下游服务聚合:

  • AdminHost(5241):/adminapi/*
  • UserHost(5245):/api/*(HTTP)、/loginhub/*(Hub)
  • CustomerHost(5247):/customerapi/*(HTTP)、/customerHub/*(Hub)
  • ChessGameHost(5242):/chess/*(HTTP)、/chessgamehub/*(Hub)
  • FishRoomHost(5244):/fishingroomhub/*(Hub)
  • FishGameHost(5248):/gamehub/*(Hub,下游为 /fishinghub/*)

7.2 附加说明(以实际配置为准)

  • 超时 / 重试 / 熔断:虽然注册了 AddPolly()(Ocelot.Provider.Polly),但 ocelot.json 的所有路由均未配置 QoSOptions,因此当前没有按路由设置的自定义超时、重试或熔断策略(csproj 已具备该能力,可按需在路由中启用)。
  • 缓存:已注册 AddCacheManager(...WithDictionaryHandle())(内存字典缓存),但路由中未配置 FileCacheOptions,因此当前没有开启任何按路由的输出缓存。
  • 限流:csproj 引用了 AspNetCoreRateLimit 5.0.0,但 Program.cs 未注册相关服务或中间件,故当前未启用限流。
  • 鉴权:路由中无 AuthenticationOptions,网关不校验身份;鉴权由下游各 Host 完成。
  • CORS:Program.cs 与 ocelot.json 均未配置 CORS。
  • 日志:网关使用 ASP.NET Core 内置日志,级别由 appsettings.json / Config/system.json 的 Logging.LogLevel 控制(Default=Information、Microsoft.AspNetCore=Warning);网关工程未接入 NLog(NLog 为平台其他服务的日志方案)。
  • 健康检查:网关暴露 /health(app.MapHealthChecks("/health")),可用于存活探测;docker-compose.yaml 未配置 healthcheck 指令。
  • 转发头:网关对 127.0.0.1、::1、172.19.0.1 作为可信代理,处理 X-Forwarded-For / X-Forwarded-Proto,使下游能获得真实客户端 IP 与协议。
  • 配置热重载:ocelot.json 以 reloadOnChange:true 加载,修改路由后可热更新,无需重启进程。