# 网关模块(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`(同时在 `` 中声明为 `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` 设置 `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`)。 ```text 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`(``),但该文件当前并未存在于 `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` 加载,修改路由后可热更新,无需重启进程。