ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

网关实战:用 TaoToken 统一 Key 聚合 Swagger API 文档

网关实战:用 TaoToken 统一 Key 聚合 Swagger API 文档 1. 多服务 Swagger 分散文档入口到底该怎么收口如果你手上维护的是三五个甚至九个微服务大概率遇到过这种场景每个服务自己带一份 Swagger UI前端同学要记user-service:8081/swagger-ui.html、order-service:8082/swagger-ui.html、pay-service:8083/doc.html环境一多地址还得跟着换。更麻烦的是鉴权每个服务的文档页要么全放开要么各自配一套白名单入口不统一安全边界也就跟着糊了。我这次要落地的目标很明确把网关作为唯一文档入口所有服务的 Swagger 资源在网关层聚合同时用 TaoToken 统一 Key 做一层校验让文档访问也走同一套 API 通道。这样客户端只需要记住一个地址鉴权逻辑只维护一份新增服务时改路由配置就行不用再挨个通知前端改地址。这篇会给出可复制的网关路由骨架、Swagger 聚合配置、统一 Key 校验片段并演示一次聚合文档访问和一次鉴权失败的验证动作。适合正在做微服务网关收口、或者被多份 Swagger 地址折磨过的后端同学。下面所有配置我都按能直接跑通的标准写参数含义会逐个说明。2. TaoToken 前置统一 Key 与 API 通道准备在动手改网关之前先把统一 Key 这条通道准备好。TaoToken 在这里承担的角色是统一 Key 管理和 API 通道收口网关校验请求时拿到的 Key 就是从这里签发的文档入口和业务接口共用同一套凭证体系不用再为文档单独造一套鉴权。你需要先拿到一个可用的 Key。进入控制台创建 API Key路径是 console 页面创建后复制保存后面网关配置里会用到。如果你还没决定用哪种接入方式可以先在模型对话里跑一次请求确认 Key 本身可用再去接网关这样排障时能快速区分是 Key 问题还是网关配置问题。具体入口我列一下按需取用控制台创建和管理 Keyhttps://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewriteAPI Key 管理页https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite接入文档网关校验字段、请求头格式以这里为准https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite模型对话快速验证 Keyhttps://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewriteAPI 基础地址是https://taotoken.net/api注意这个地址不带任何查询参数网关转发时直接用它作为上游前缀即可。Key 的请求头字段名和鉴权格式以接入文档为准不同版本可能有细微差异配置前扫一眼文档能省掉一次 401 排查。注意Key 属于凭证不要写进前端代码或提交到公开仓库。网关侧建议用环境变量或配置中心注入本地调试用.env文件并加入.gitignore。3. 可复制配置网关路由 Swagger 聚合 统一 Key 校验这一节是核心分三块网关路由骨架、Swagger 资源聚合配置、统一 Key 校验片段。我按 Spring Cloud Gateway 的写法给其他网关比如 Nginx、Kong思路一致路由和鉴权拆开处理即可。3.1 网关路由骨架先在网关的配置文件里定义各服务的路由把文档路径和业务路径都指向对应服务。下面这段是 YAML 骨架uri换成你实际的服务地址predicates里的路径按服务名调整spring: cloud: gateway: routes: - id: user-service uri: lb://user-service predicates: - Path/user/** filters: - StripPrefix1 - id: order-service uri: lb://order-service predicates: - Path/order/** filters: - StripPrefix1 - id: pay-service uri: lb://pay-service predicates: - Path/pay/** filters: - StripPrefix1StripPrefix1的作用是转发时去掉第一段路径比如/user/v2/api-docs转发到user-service时变成/v2/api-docs这样各服务的 Swagger 端点不用改。如果你的服务本身带 context-path这里要相应调整。3.2 Swagger 资源聚合配置网关聚合 Swagger 的关键是提供一个SwaggerResourcesProvider把各服务的文档地址拼出来。下面这段可以直接放进网关模块Component Primary public class GatewaySwaggerResourcesProvider implements SwaggerResourcesProvider { private static final String SWAGGER2URL /v2/api-docs; private final RouteLocator routeLocator; Value(${spring.application.name}) private String self; public GatewaySwaggerResourcesProvider(RouteLocator routeLocator) { this.routeLocator routeLocator; } Override public ListSwaggerResource get() { ListSwaggerResource resources new ArrayList(); ListString routeHosts new ArrayList(); routeLocator.getRoutes() .filter(route - route.getUri().getHost() ! null) .filter(route - !self.equals(route.getUri().getHost())) .subscribe(route - routeHosts.add(route.getUri().getHost())); SetString dealed new HashSet(); routeHosts.forEach(instance - { String url / instance.toLowerCase() SWAGGER2URL; if (!dealed.contains(url)) { dealed.add(url); SwaggerResource swaggerResource new SwaggerResource(); swaggerResource.setUrl(url); swaggerResource.setName(instance); resources.add(swaggerResource); } }); return resources; } }这里有个坑我踩过SWAGGER2URL必须是/v2/api-docs如果你用的是 Swagger 3 或者 OpenAPI 3端点可能是/v3/api-docs但聚合 UI 对 v2 格式兼容更好很多情况下用 v2 端点反而更稳。如果服务只暴露 v3可以在服务侧加一个 v2 兼容端点或者把常量改成/v3/api-docs后测试 UI 是否正常渲染。3.3 统一 Key 校验片段文档入口也要走鉴权这里加一个全局过滤器对文档路径做 Key 校验。校验逻辑是从请求头取 Key调用 TaoToken 的校验接口或本地校验通过则放行不通过返回 401。Component public class UnifiedKeyFilter implements GlobalFilter, Ordered { private static final String KEY_HEADER Authorization; private static final String TAOTOKEN_VERIFY_URL https://taotoken.net/api; Override public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { String path exchange.getRequest().getURI().getPath(); // 只对文档相关路径做校验业务路径按原有鉴权走 if (!path.contains(/v2/api-docs) !path.contains(/doc.html) !path.contains(/swagger-resources)) { return chain.filter(exchange); } String key exchange.getRequest().getHeaders().getFirst(KEY_HEADER); if (key null || key.isBlank()) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } // 这里调用 TaoToken 校验接口实际字段以接入文档为准 return verifyKey(key) .flatMap(valid - { if (Boolean.TRUE.equals(valid)) { return chain.filter(exchange); } exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); }); } private MonoBoolean verifyKey(String key) { // 伪代码实际用 WebClient 调 TaoToken 校验端点 // 返回 true 表示 Key 有效 return Mono.just(key.startsWith(sk-)); } Override public int getOrder() { return -100; } }getOrder()返回-100是为了让这个过滤器在路由转发之前执行避免请求已经打到下游服务才做校验。校验接口的具体地址和请求格式以接入文档为准我这里用startsWith(sk-)只是占位实际要替换成真实调用。3.4 白名单与放行配置网关如果集成了 Spring Security需要把 Swagger 相关路径加进白名单否则 UI 静态资源会被拦。配置如下oauth: server: ignore: urls: - /swagger-ui.html - /swagger-ui/* - /swagger-resources/** - /v2/api-docs - /v3/api-docs - /webjars/** - /doc.html - /**/v2/api-docs注意最后一条/**/v2/api-docs它匹配的是各服务前缀下的文档端点比如/user/v2/api-docs。少了这条聚合 UI 拉取子服务文档时会 404。4. 验证请求与成功结果配置写完启动网关做两步验证先验证聚合文档能正常访问再验证鉴权失败时的返回。4.1 聚合文档访问验证浏览器访问http://localhost:9000/doc.html如果配置正确页面右上角会出现服务下拉框里面列出user-service、order-service、pay-service等。切换服务能看到对应接口列表说明聚合成功。用 curl 验证文档端点是否可达curl -H Authorization: sk-your-key-here \ http://localhost:9000/user/v2/api-docs返回应该是该服务的 OpenAPI JSON包含swagger、paths、definitions等字段。如果返回 401说明 Key 校验没通过返回 404说明路由或StripPrefix配置有问题。4.2 鉴权失败验证故意不带 Key 请求文档端点curl -i http://localhost:9000/user/v2/api-docs预期返回HTTP/1.1 401 Unauthorized再带一个格式错误的 Keycurl -i -H Authorization: invalid-key \ http://localhost:9000/user/v2/api-docs同样应该返回 401。这两步能确认统一 Key 校验生效文档入口没有裸奔。4.3 成功结果说明当带正确 Key 请求时返回 200 和文档 JSON不带或带错 Key 时返回 401。聚合 UI 页面在带 Key 的情况下能正常加载各服务文档切换服务不报错。到这里文档入口就完成了从「多地址分散」到「单入口 统一 Key」的收口。5. 本篇常见错排查配置过程中容易踩的坑我整理成表格对照排查能省不少时间现象可能原因处理方式聚合 UI 下拉框为空SwaggerResourcesProvider没生效或路由 host 为空检查Primary是否加路由uri是否用lb://且服务已注册子服务文档 404StripPrefix配置不对或白名单缺/**/v2/api-docs调整StripPrefix值补白名单文档页 401Key 校验过滤器拦截了静态资源白名单放行/doc.html、/webjars/**等返回 v3 格式 UI 渲染异常服务只暴露/v3/api-docs服务侧加 v2 兼容端点或改常量后测试Key 校验总是失败请求头字段名或格式与文档不一致对照接入文档确认字段名和前缀网关启动报路由冲突多个路由id重复或路径重叠检查id唯一性调整Path优先级如果排查到 Key 本身的问题比如不确定 Key 是否有效可以去模型对话页面单独发一次请求验证排除网关因素。如果是接入字段的问题直接翻接入文档比猜快得多。6. 收口之后文档入口与业务接口共用一套 Key走到这里网关层的 Swagger 聚合和统一 Key 校验已经跑通。回顾一下做了什么路由骨架把各服务路径收进来SwaggerResourcesProvider把文档资源聚合到一个 UI全局过滤器对文档路径做 Key 校验白名单放行静态资源。最终效果是一个地址http://gateway:9000/doc.html看所有服务文档一个 Key 管所有入口。后续新增服务时只需要在路由配置里加一段聚合 UI 会自动发现新服务不用改前端地址也不用单独配文档鉴权。如果团队开始做长期编码或 Agent 集成可以把这套 Key 通道复用到 Coding Plan 场景文档和代码生成共用同一套凭证减少维护面。长期编码 / Agent 接入https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewriteClaude Code 接入说明https://taotoken.net/claude-code?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecodeutm_campaignrewrite最后留一个实操建议把网关的 Key 校验过滤器写成可配置的路径匹配而不是硬编码contains这样以后要调整哪些路径需要校验改配置就行不用重新发版。我试过用PathPatternParser做匹配比字符串contains更准也不会误伤名字里带doc的业务接口。
返回列表