ARTICLE DETAIL

资讯详情

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

初识服务网关之Spring Cloud Gateway:从路由断言到统一鉴权的配置骨架

初识服务网关之Spring Cloud Gateway:从路由断言到统一鉴权的配置骨架 1. 为什么你的微服务需要一个统一入口如果你正在做 Spring Cloud 微服务大概率会遇到这样一个尴尬局面用户服务、订单服务、支付服务各自跑在不同的端口上前端同学每次联调都要问“这个接口在哪个端口来着”。更麻烦的是鉴权逻辑散落在每个服务里改一次 Token 校验规则要动五个仓库。这时候Spring Cloud Gateway 就该登场了。Spring Cloud Gateway 是 Spring Cloud 生态里的 API 网关组件专门为微服务架构设计。它基于 Netty 做非阻塞 I/O性能比老一代的 Zuul 1.x 好不少而且和 Spring Cloud 的服务发现、负载均衡、配置中心天然打通。简单说它干的事就是所有外部请求先打到网关网关根据你配的规则决定转发给哪个后端服务转发前后还能插一层过滤器做鉴权、加头、限流、改路径。它适合谁适合已经在用 Spring Cloud 做微服务拆分、需要一个统一流量入口的团队也适合刚学微服务、想跑通第一个网关实例的开发者。这篇不聊虚的直接给你一套能复制的application.yml路由与过滤器骨架再带你用 curl 验证转发和鉴权拦截到底有没有生效。2. 动手前先把网关的骨架搭起来2.1 依赖与版本对齐新建一个 Spring Boot 项目或者在你现有的工程里加模块。核心依赖就一个spring-cloud-starter-gateway再加个 Actuator 方便看路由状态。注意Gateway 是响应式的别把spring-boot-starter-web一起引进来否则会冲突启动报错。dependencyManagement dependencies dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-dependencies/artifactId version2023.0.1/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement dependencies dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-gateway/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-actuator/artifactId /dependency /dependencies版本上Spring Boot 3.x 对应 Spring Cloud 2023.xSpring Boot 2.7 对应 2021.x。版本对不上会在启动时抛NoSuchMethodError这是新手最容易踩的坑。2.2 三个核心概念用一句话说清Route路由是转发的基本单位一个路由 一个 ID 一个目标 URI 一组断言 一组过滤器。Predicate断言负责判断“这个请求该不该走这条路由”比如路径是不是/order/**。Filter过滤器负责在转发前后动手脚比如加个请求头、校验 Token、重写路径。你可以把网关想象成公司前台Route 是“访客去哪个部门”Predicate 是“什么条件的访客才放行”Filter 是“进门先登记、发访客牌”。3. 可复制的路由与鉴权配置骨架3.1 application.yml 完整骨架下面这份配置包含两条路由一条转发到订单服务并做路径重写一条转发到用户服务并挂上自定义鉴权过滤器。你可以直接改 URI 和路径用起来。server: port: 9000 spring: application: name: api-gateway cloud: gateway: routes: - id: order_service uri: http://localhost:8081 predicates: - Path/api/order/** filters: - StripPrefix2 - AddRequestHeaderX-Gateway-Source, spring-cloud-gateway - name: Auth - id: user_service uri: http://localhost:8082 predicates: - Path/api/user/** - MethodGET,POST filters: - StripPrefix2 - name: Auth management: endpoints: web: exposure: include: gateway,health,info这里StripPrefix2的意思是去掉路径前两段/api/order/create转发到后端就变成/create。AddRequestHeader给每个请求加一个来源标记后端服务可以据此判断请求是否经过网关。3.2 自定义鉴权过滤器光靠内置过滤器做不了 Token 校验得自己写一个。实现GlobalFilter接口对所有路由生效检查请求头里有没有Authorization没有就直接返回 401有就放行。import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.http.HttpStatus; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; Component public class AuthGlobalFilter implements GlobalFilter, Ordered { Override public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpRequest request exchange.getRequest(); String path request.getPath().value(); // 放行健康检查和登录接口 if (path.contains(/actuator) || path.contains(/api/user/login)) { return chain.filter(exchange); } String token request.getHeaders().getFirst(Authorization); if (token null || !token.startsWith(Bearer )) { exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } // 把用户信息透传给下游服务 ServerHttpRequest mutated request.mutate() .header(X-User-Token, token.substring(7)) .build(); return chain.filter(exchange.mutate().request(mutated).build()); } Override public int getOrder() { return -100; } }getOrder()返回-100是为了让鉴权过滤器在路由转发之前执行数字越小优先级越高。如果你想让某个过滤器只作用于特定路由可以实现GatewayFilterFactory然后在 yml 里用name引用。3.3 过滤器链的执行顺序请求进来后过滤器链按 order 从小到大执行。全局过滤器和路由过滤器会合并排序。一个典型链路是鉴权过滤器-100→ 请求头添加0→ 路径重写0→ 转发到后端。响应回来时按相反顺序再走一遍。理解这个顺序排查“为什么头没加上”这类问题时特别有用。4. 启动网关用 curl 验证转发与拦截4.1 启动与路由检查启动网关应用后先访问 Actuator 端点确认路由加载成功curl http://localhost:9000/actuator/gateway/routes返回的 JSON 里应该能看到order_service和user_service两条路由以及各自的 predicates 和 filters。如果这里是空的说明 yml 缩进有问题或者路由没被扫描到。4.2 验证路由转发假设你的订单服务在 8081 端口有一个/create接口。不带 Token 直接请求curl -i http://localhost:9000/api/order/create预期返回401 Unauthorized因为鉴权过滤器拦住了。这说明过滤器生效了。带上 Token 再请求curl -i -H Authorization: Bearer test-token-123 http://localhost:9000/api/order/create这次应该返回订单服务的真实响应。同时你可以在订单服务里打印请求头确认X-Gateway-Source和X-User-Token都透传过来了。4.3 验证路径重写在订单服务里加一个接口打印request.getRequestURI()。请求/api/order/create时后端收到的应该是/create。如果收到的还是完整路径检查StripPrefix的数字对不对——它数的是路径段数/api/order/create去掉两段正好剩/create。5. 本篇常见错误排查启动报错Spring MVC found on classpath说明你同时引了spring-boot-starter-web。Gateway 基于 WebFlux和 MVC 互斥。把 web 依赖排除掉或者用spring.main.web-application-typereactive强制指定。路由 404先看/actuator/gateway/routes里路由在不在。在的话检查Path断言写的是不是/api/order/**注意**和*的区别*只匹配一段。再看StripPrefix是不是把路径去多了。鉴权过滤器不生效确认类上有Component并且实现了GlobalFilter。如果用的是GatewayFilterFactory要在 yml 里用name显式引用光加Component不会自动挂到路由上。请求头透传丢失Gateway 默认会过滤掉一些敏感头比如Cookie、Set-Cookie。如果你要透传自定义头确认头名不在默认黑名单里。另外AddRequestHeader加的头下游用getHeader能拿到但不会出现在getHeaderNames的某些实现里这是正常的。跨域问题前端调网关报 CORS 错误在 yml 里加globalcors配置或者写一个CorsWebFilter。注意不要同时在网关和后端服务都配 CORS会重复加头导致浏览器报错。6. 把网关接上模型服务做联调网关跑通之后下一步通常是把它接到真实的业务服务上。如果你在本地调试时需要频繁调用大模型接口来验证网关的转发和鉴权逻辑可以先把模型对话入口配好用真实的请求链路压一压过滤器链。TaoToken 的模型对话入口在这里https://taotoken.net/api?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite如果你打算把网关作为长期编码或 Agent 项目的统一入口需要先拿到 API Key 并配置到网关的下游服务里Key 的创建入口在控制台https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite接入文档里有完整的请求格式和参数说明配网关转发规则时对着看能少走弯路https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite如果你更偏向在 IDE 里直接调模型来验证网关链路Coding Plan 的入口在这里https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite网关的价值在于把鉴权、限流、日志这些横切关注点从各个微服务里抽出来集中在一层处理。你先把上面这套骨架跑通再根据业务往里加限流、熔断、灰度就是水到渠成的事了。
返回列表