资讯动态

SpringCloud集成微服务API网关Gateway(详解):从路由断言到统一鉴权的可复制配置

发布时间:2026/10/17 17:17:49 来源:尧图企业网站定制
1. 为什么微服务入口需要一个 Gateway从订单服务被刷爆说起如果你正在用 SpringCloud 做微服务大概率会遇到这样一个场景前端同学拿着三个不同的域名来找你说订单、支付、用户服务各调各的跨域配了三遍还是报错运维同学又跑来说某个服务没做鉴权被人直接扫到了内部接口。这时候你需要的不是给每个服务再写一遍过滤器而是在所有微服务前面放一个统一入口这就是 SpringCloud Gateway 要解决的问题。SpringCloud Gateway 是 SpringCloud 官方推出的 API 网关组件基于 Spring5 的 WebFlux 响应式编程模型实现和早期基于 Servlet 阻塞式模型的 Zuul 相比在高并发场景下资源占用更低、吞吐更好。它能做的事情可以概括成五类路由转发把/orderservice/**的请求转给订单服务负载均衡同一个服务起三个实例时自动分发统一鉴权在网关层校验 Token不合法的请求根本进不了微服务流量控制按请求频率限流监控日志所有进出流量在网关层统一记录。这篇文章面向的是已经搭好 SpringCloud 工程、注册中心用 Nacos、服务间调用用 OpenFeign 的开发者。我会从零搭一个cloud-gateway模块把路由断言、过滤器链、全局鉴权、跨域配置一次性配好并且给出用 curl 验证每一步的具体命令。网关层跑通之后我还会顺带讲一下怎么把网关后面的模型调用通道统一收口到 TaoToken 的 API 通道上让 Key 管理也集中到网关这一层避免每个服务各存一份密钥。适合谁看能看懂application.yml、写过RestController、知道 Nacos 是干什么的 Java 后端。如果你连 SpringBoot 工程都没建过建议先把基础工程跑起来再回来。整篇的节奏是先讲清楚问题再给可复制配置然后验证最后排错你可以边看边在本地敲。2. TaoToken 前置准备把模型调用通道收口到网关层在讲网关配置之前先说一下为什么要在网关这个位置接入 TaoToken。微服务架构里订单服务、支付服务、客服服务可能都需要调用大模型能力如果每个服务各自维护一份 API Key密钥散落在各个配置文件里轮换一次要改五六个地方还容易漏。更合理的做法是让所有模型请求先经过网关由网关统一持有 Key 并转发微服务只面向网关的内网地址。TaoToken 提供的是统一的模型 API 通道官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。它的作用是把不同模型的调用协议统一成一套兼容 OpenAI 格式的接口你在网关里只需要配一个上游地址和一个 Key后面接哪个模型由请求里的 model 字段决定。前置准备分三步。第一步注册账号后进入控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 在 API Keys 页面创建一个 Key页面地址是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 创建后立刻复制保存页面刷新后就不再完整显示。第二步确认你要用的模型 ID可以在模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 里先手动发一条消息确认通道可用同时记下模型名称。第三步如果你打算长期做编码类 Agent 或者多轮工具调用可以看一下 Coding Plan 页面 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 它面向的是持续编码场景和按次调用的计费方式不同。这里要强调一点TaoToken 是合规的 API 通道服务你在网关里配置它本质上是把网关当成一个反向代理把/ai/**的请求转发到https://taotoken.net/api并附上 Authorization 头。网关本身不改变请求语义也不做任何协议转换之外的事情。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 遇到字段对不上时以文档为准。准备好 Key 和模型 ID 之后我们进入网关模块的搭建。注意网关层持有 Key 意味着这个模块的配置文件敏感度最高生产环境建议用配置中心加密或者环境变量注入不要明文提交到 Git。3. 可复制配置application.yml 路由断言与过滤器链先建模块。在父工程下新建cloud-gateway模块pom.xml里引入两个核心依赖网关依赖和服务发现依赖。如果你用bootstrap.yml还要额外引入 bootstrap 启动器否则配置不会被加载图省事的话直接用application.yml也可以。dependencies dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-gateway/artifactId /dependency dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-bootstrap/artifactId /dependency /dependencies这里有个高频坑如果你的网关模块里混进了spring-boot-starter-web启动会直接报Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway。解决办法是移除 web 依赖或者在配置里显式声明spring.main.web-application-type: reactive。我建议直接移除避免后面有人手滑又加回来。下面是完整的application.yml包含 Nacos 注册、两条路由、默认过滤器、全局跨域以及一条指向 TaoToken 的 AI 通道路由。路径和原文保持一致你可以直接复制后改服务名。server: port: 10717 spring: application: name: gateway profiles: active: dev main: web-application-type: reactive cloud: nacos: server-addr: localhost:8848 discovery: cluster-name: HZ namespace: cdd2a801-3280-4476-8362-d46318aac1a3 gateway: routes: - id: orderservice uri: lb://orderservice predicates: - Path/orderservice/** filters: - AddRequestHeaderAuthorization,token-Bearer-5S3ZURuoTkN95zkG1QQ7eo7AHS7WA - id: paymentservice uri: lb://paymentservice predicates: - Path/paymentservice/** - id: taotoken-ai uri: https://taotoken.net/api predicates: - Path/ai/** filters: - StripPrefix1 - AddRequestHeaderAuthorization,Bearer ${TAOTOKEN_API_KEY} default-filters: - AddRequestHeaderX-Gateway-Source,cloud-gateway globalcors: add-to-simple-url-handler-mapping: true cors-configurations: [/**]: allowedOrigins: - http://localhost:10717 - http://localhost:8088 allowedMethods: - GET - POST - DELETE - PUT - OPTIONS allowedHeaders: * allowCredentials: true maxAge: 360000逐段解释。routes下每条路由有四个要素id是唯一标识随便起但别重复uri支持http和lb两种lb://orderservice表示走负载均衡到 Nacos 里注册的 orderservice 实例predicates是断言Path/orderservice/**表示路径以/orderservice/开头就命中filters是这条路由专属的过滤器。default-filters里的过滤器对所有路由生效我加了一个X-Gateway-Source头方便后端服务确认请求确实经过了网关。globalcors解决跨域add-to-simple-url-handler-mapping: true是为了让 OPTIONS 预检请求不被拦截这个不加的话前端会一直报跨域。taotoken-ai这条路由值得单独说。StripPrefix1会把/ai前缀去掉所以请求/ai/v1/chat/completions转发到上游时变成https://taotoken.net/api/v1/chat/completions。AddRequestHeader把 Key 注入到 Authorization 头${TAOTOKEN_API_KEY}从环境变量读取避免明文。启动前记得export TAOTOKEN_API_KEY你的Key。启动类很简单SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); System.out.println(Gateway 网关服务启动成功); } }启动后看控制台有没有报错然后打开 Nacos 控制台确认gateway服务已经注册进去。如果注册不上先检查server-addr和namespace是否和你的 Nacos 一致。4. 验证请求用 curl 跑通路由转发与鉴权拦截配置写完不验证等于没写。这一节我用 curl 把路由转发、默认过滤器、全局鉴权、AI 通道四条链路都跑一遍每条都给出预期结果。先验证基础路由转发。假设 orderservice 里有个接口/system/order/getToken它返回请求头里的 Authorizationcurl -i http://localhost:10717/orderservice/system/order/getToken预期返回 200body 里data字段是token-Bearer-5S3ZURuoTkN95zkG1QQ7eo7AHS7WA说明路由转发成功且路由过滤器注入的请求头被后端读到了。如果返回 404检查 orderservice 是否注册到同一个 namespace以及 Path 断言是否写对。再验证默认过滤器。paymentservice 没有单独配 Authorization 过滤器但 default-filters 会生效curl -i http://localhost:10717/paymentservice/payment/getToken预期同样能拿到token-Bearer-...证明默认过滤器对所有路由生效。这一步能过说明过滤器链的合并逻辑正常。接着验证全局鉴权。写一个AuthorizeFilter实现GlobalFilter和Ordered从 query 参数里取 Authorization和静态 Token 比对不合法直接返回 401Component public class AuthorizeFilter implements GlobalFilter, Ordered { private static final String STATIC_TOKEN token-Bearer-5S3ZURuoTkN95zkG1QQ7eo7AHS7WA; Override public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request exchange.getRequest(); MultiValueMapString, String params request.getQueryParams(); String authToken params.getFirst(Authorization); if (STATIC_TOKEN.equals(authToken)) { return chain.filter(exchange); } exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } Override public int getOrder() { return -1; } }错误请求curl -i http://localhost:10717/paymentservice/payment/getToken?Authorization1234预期返回HTTP/1.1 401 Unauthorized。正确请求curl -i http://localhost:10717/paymentservice/payment/getToken?Authorizationtoken-Bearer-5S3ZURuoTkN95zkG1QQ7eo7AHS7WA预期返回 200 和正常 JSON。这两条一对比鉴权拦截就验证完了。最后验证 AI 通道。先确认环境变量已导出然后curl -i -X POST http://localhost:10717/ai/v1/chat/completions \ -H Content-Type: application/json \ -d {model:你的模型ID,messages:[{role:user,content:你好}]}预期返回 200 和模型回复。如果返回 401说明 Key 没注入成功检查环境变量名是否和 yml 里一致。这一步跑通意味着网关不仅能转发内部微服务还能作为模型调用的统一出口。5. 本篇常见错排查401、local proxy failed 与 reading choices网关配置踩坑集中在几个固定报错上我把它们和对应原因列出来你对照着改。第一个是启动报Spring MVC found on classpath。原因前面说过网关模块混进了spring-boot-starter-web。解决方式是移除该依赖或者加spring.main.web-application-type: reactive。我建议移除因为响应式网关和 Servlet 容器同时存在时过滤器链行为会变得不可预测。第二个是请求返回 401但你的 Token 明明是对的。常见原因有三个一是全局过滤器的 order 值太大排在路由过滤器后面执行导致请求已经被转发二是 Token 从 header 取但你写成了 query 参数三是AddRequestHeader注入的 Key 里多了空格。排查时先在过滤器里打印exchange.getRequest().getHeaders()确认请求头内容。第三个是local proxy failed或者连接被拒。这通常发生在uri写成了http://127.0.0.1:18088但服务实际端口不是这个或者服务没注册到 Nacos 导致lb://解析不到实例。用curl直接打服务端口确认服务活着再去 Nacos 控制台看实例列表。第四个是调用 AI 通道时返回reading choices相关错误或者响应体解析失败。这类报错一般不是网关的问题而是上游返回了非预期结构。先用curl直接打https://taotoken.net/api/v1/chat/completions确认通道本身可用再对比网关转发后的请求体是否被StripPrefix改错了路径。如果路径多剥了一层或少剥了一层choices字段自然读不到。第五个是跨域仍然报错。检查add-to-simple-url-handler-mapping是否为 true以及allowedOrigins里有没有包含你前端的实际地址。注意allowCredentials: true时allowedOrigins不能用*必须写具体域名。第六个是过滤器执行顺序不符合预期。记住规则order 值越小越先执行路由过滤器和默认过滤器的 order 由 Spring 按声明顺序从 1 递增order 相同时按默认过滤器、路由过滤器、全局过滤器的顺序。想看真实顺序在FilteringWebHandler的handle方法打断点或者把日志级别调到 DEBUG。如果你在网关后面接的是 Claude Code 这类编码工具配置时三件套要写全Base URL 填https://taotoken.net/apiKey 填你创建的 KeyModel ID 填控制台里确认的模型名。缺任何一个都会报鉴权或模型不存在。接入细节以 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 为准。6. 把网关作为统一出口Key 管理与后续扩展网关跑通之后你会发现它的价值不只是路由。所有外部请求都从这里进意味着鉴权、限流、日志、Key 管理都可以收口在这一层。我现在的做法是微服务之间用内网直连只有网关暴露公网端口模型调用的 Key 只存在网关的环境变量里业务服务通过网关的/ai/**路由间接调用服务本身不接触密钥。这样做的好处是轮换 Key 时只改一个地方重启网关即可业务服务无感。如果你后面要接多个模型供应商也可以在网关层加一条路由用不同的 Path 前缀区分比如/ai-a/**和/ai-b/**各自注入不同的 Key。再进一步可以结合RequestRateLimiter过滤器做限流防止某个服务把配额打满。需要提醒的是网关层持有 Key 也意味着它是安全等级最高的模块。生产环境建议把 Key 放到配置中心并加密或者用 K8s Secret 注入环境变量不要写死在 yml 里提交到代码仓库。另外全局过滤器里做鉴权时记得把健康检查路径和登录接口放行否则 Nacos 的健康检查会被 401 拦掉。如果你打算长期用这套架构做编码 Agent 或者多轮工具调用可以了解一下 Coding Plan它面向的是持续编码场景和按次调用的计费方式不同适合把网关作为统一出口后长期跑任务的团队。模型对话页面可以用来快速验证某个模型 ID 是否可用省得每次都发 curl。最后留一个实操建议把本文的application.yml存成模板每接一个新服务只改id、uri和Path三处其余照抄。过滤器链和跨域配置一次配好后面基本不用动。网关这东西配对了就一劳永逸配错了就是所有请求一起挂所以每次改完务必用 curl 把四条链路各跑一遍再上线。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑