16 KiB
网关模块(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 实现,是整个平台的统一流量入口。其定位与职责如下:
- 统一入口:前端(用户端、客服端、后台管理端、游戏端)只需访问网关地址
http://localhost:8001,无需关心后端各服务的真实地址与端口。 - 路由转发:依据
ocelot.json中声明式的Routes配置,把上游(Upstream)请求按路径模板转发到对应下游(Downstream)服务。 - 反向代理与转发头处理:通过
ForwardedHeaders中间件处理X-Forwarded-For/X-Forwarded-Proto,保证后端服务能拿到真实客户端 IP 与协议(配置了可信代理白名单)。 - 健康检查:暴露
/health健康检查端点。 - WebSocket / SignalR 透传:Ocelot 原生支持 WebSocket,网关同时承载各服务的 SignalR Hub 路径(见第三节)。
- 可扩展的横切能力(已注册但当前未按路由启用):
- 已引入并注册 缓存(
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 包:
包名 版本 作用 Ocelot20.0.0 API 网关核心 Ocelot.Cache.CacheManager20.0.0 Ocelot 输出缓存扩展 Ocelot.Provider.Polly20.0.0 Ocelot 的 Polly 集成(QoS:超时/重试/熔断) AspNetCoreRateLimit5.0.0 限流库(已在 csproj 引用,但代码中未启用) -
内容拷贝设置:
appsettings.json→CopyToOutputDirectory=Alwaysocelot.json→CopyToOutputDirectory=Always(同时在<None>中声明为PreserveNewest)docker-compose.yaml→CopyToOutputDirectory=AlwaysDockerfile→CopyToOutputDirectory=Always(注意:csproj 中引用了Dockerfile,但当前工程目录下实际不存在该文件)
4.2 启动流程(Program.cs)要点
入口为顶层语句(Top-level statements),核心逻辑:
- 配置加载:
builder.Configuration.AddJsonFile("ocelot.json", optional: false, reloadOnChange: true)——ocelot.json为必需文件,且支持热重载(修改路由配置无需重启)。builder.Configuration.AddJsonFile(Path.Combine("Config", "system.json"), optional: true)——Config\system.json为可选补充配置。
- 注册 Ocelot:
builder.Services.AddOcelot(builder.Configuration).AddCacheManager(x => x.WithDictionaryHandle()).AddPolly()- 使用内存字典(
WithDictionaryHandle)作为缓存存储; - 启用 Polly 提供者(具备 QoS 能力,但路由中未配置
QoSOptions)。
- 使用内存字典(
- 健康检查:
builder.Services.AddHealthChecks()。 - 转发头配置:
Configure<ForwardedHeadersOptions>设置XForwardedFor | XForwardedProto,清空默认已知代理/网络后,加入可信代理127.0.0.1、::1(IPv6)、172.19.0.1(其中172.17.0.1、172.18.0.1被注释掉)。 - 中间件管道:
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加载,修改路由后可热更新,无需重启进程。