Hot Chocolate GraphQL Stitching 如何根据变量值路由查询/变更请求
方案适配性结论
你这个Schema完全一致、按请求变量region值分流到不同后端的场景,GraphQL Stitching完全适配,属于它的自定义路由能力覆盖范围,不需要额外自研转发层。
和直接在Azure APIM层写转发规则比,Stitching天然兼容GraphQL协议的所有特性(批量请求、订阅、错误格式标准化、查询校验),不用自己写逻辑解析GraphQL请求结构、处理协议细节,长期维护成本低很多。
具体实现思路
- 第一步:网关注册多后端数据源
把每个region对应的后端服务,作为同Schema的远程源注册到Stitched网关,给每个源绑定对应region标签,比如Country1对应的后端绑定标签Country1Backend、Country2对应Country2Backend。因为所有后端Schema完全一致,注册时直接关闭默认的类型重写、跨源字段合并逻辑,避免不必要的性能损耗。 - 第二步:编写自定义路由拦截逻辑
核心是在网关的请求执行管道最前面加拦截器,逻辑非常简单:- 从请求的顶层variables集合里直接读取
region字段值,不需要深度遍历查询AST,性能开销可以忽略 - 校验
region值是否在合法枚举范围内,非法值直接返回标准GraphQL参数错误,不往后转发 - 根据读取到的region值,匹配对应标签的后端数据源,将整个请求原样转发到对应后端即可,不需要做任何查询改写
如果你用Hot Chocolate做.NET栈的Stitching网关,核心实现代码参考:
// 注册不同region的后端HttpClient services.AddHttpClient("Country1Backend", cli => cli.BaseAddress = new Uri("https://country1-service-endpoint")); services.AddHttpClient("Country2Backend", cli => cli.BaseAddress = new Uri("https://country2-service-endpoint")); services.AddGraphQLServer() // 注册两个同Schema的远程源 .AddRemoteSchema("Country1Backend", ignoreRootTypes: false) .AddRemoteSchema("Country2Backend", ignoreRootTypes: false) // 关闭默认的类型重写,因为两边Schema完全一致 .AddTypeNameRewriter((_, _) => default) // 加自定义路由拦截逻辑 .UseRequest(async (context, next) => { if (context.Variables.TryGetVariable("region", out string region)) { context.SetSelectedSchema(region switch { nameof(Region.Country1) => "Country1Backend", nameof(Region.Country2) => "Country2Backend", _ => throw new GraphQLException("Invalid region parameter") }); } await next(context); }); - 从请求的顶层variables集合里直接读取
- 第三步:适配现有Azure APIM链路
现有APIM层不需要做任何payload解析逻辑,直接把所有发往GraphQL路径的请求全量转发到Stitched网关即可。APIM层原有的鉴权、限流、WAF拦截、日志埋点逻辑全部保留,这些边缘逻辑放在APIM层性能比在业务网关层好很多。后续新增region节点时,只需要在Stitched网关加配置,不需要动APIM规则。
落地最佳实践
- Mutation不需要特殊处理:因为是全请求原样转发,Mutation请求会完整落到对应region的后端,和直接请求后端的行为完全一致,不会出现拆分Mutation导致的副作用问题。
- 缓存必须带region标识:如果在网关层开启查询缓存,缓存key必须拼接region值,绝对不能跨region复用缓存,避免不同region的业务数据串流。
- 错误透传不要过度包装:配置网关时直接透传后端返回的GraphQL错误结构,不要自定义包装错误格式,减少前端的适配成本。
- 灰度能力可以直接扩展:后续如果要做新region灰度、流量切分,直接在路由拦截逻辑里加权重判断即可,不需要调整链路其他环节。
- 极端轻量场景的备选:如果后续完全没有跨region的Schema聚合需求、也不需要GraphQL订阅/批量请求特性,也可以直接在APIM层用
set-body策略解析请求变量里的region值做转发,但这种方案需要自己处理所有GraphQL协议兼容逻辑,维护成本会高很多,非必要不选。
内容的提问来源于stack exchange,提问作者Sakkie
相关产品推荐
相关产品推荐

