ARTICLE DETAIL

资讯详情

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

【Spring Cloud】深入探索统一网关 Gateway 的搭建,断言工厂,过滤器工厂,全局过滤器以及跨域问题:把路由配置改到 TaoToken 的实操记录

【Spring Cloud】深入探索统一网关 Gateway 的搭建,断言工厂,过滤器工厂,全局过滤器以及跨域问题:把路由配置改到 TaoToken 的实操记录 1. 从零搭建 Gateway 网关最小路由跑通与微服务结构梳理Spring Cloud Gateway 是 Spring Cloud 生态里基于 WebFlux 的响应式网关它承担了统一入口、路由转发、断言匹配、过滤器链处理、跨域处理这些职责。如果你正在做微服务拆分客户端不应该直接访问每个服务的地址而是统一打到网关由网关根据路径、请求头、时间等条件决定转发到哪个服务。这篇内容我会按“先跑通最小路由 → 再逐个加断言工厂 → 加过滤器工厂 → 加全局过滤器 → 处理跨域 → 把下游调用 endpoint 与鉴权配置改到 TaoToken 统一通道”的顺序走一遍每一步都给可复制的配置和验证命令。适合谁看正在学 Spring Cloud Gateway 的同学、需要把网关从 demo 推到可联调状态的后端、以及想把模型调用统一收敛到网关后面的开发者。核心检索词就是 Spring Cloud Gateway 搭建、断言工厂、过滤器工厂、全局过滤器、跨域配置这几个概念会贯穿全文。先明确一个结构网关gateway端口 10010作为唯一入口注册到 Nacos下游有 userservice、orderservice 两个微服务也注册到 Nacos。网关通过lb://userservice这种写法做负载均衡转发。这个结构决定了后面所有配置都围绕spring.cloud.gateway.routes展开。创建模块时包结构建议是com.example.gateway启动类SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class, args); } }pom.xml 里两个关键依赖一个是网关启动器一个是 Nacos 服务发现dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-gateway/artifactId /dependency dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency注意 Gateway 是基于 WebFlux 的不要同时引入spring-boot-starter-web否则启动会报冲突这是新手最容易踩的坑之一。最小可用的 application.yml 如下server: port: 10010 spring: application: name: gateway cloud: nacos: server-addr: localhost:8848 gateway: routes: - id: user-service uri: lb://userservice predicates: - Path/user/** - id: order-service uri: lb://orderservice predicates: - Path/order/**启动 gateway、userservice、orderservice 三个服务后用 curl 验证curl -i http://127.0.0.1:10010/user/1 curl -i http://127.0.0.1:10010/order/1返回 200 且 body 是用户/订单数据说明最小路由通了。如果返回 503多半是 Nacos 里没注册上或者服务名写错返回 404 则是断言没匹配上检查 Path 是否写对。这一步是整个网关的地基后面所有断言、过滤器都挂在这条路由上。2. 断言工厂 Predicate Factory 逐个接入与命中验证断言工厂的作用是把配置文件里的字符串规则解析成真正的路由判断条件。Spring Cloud Gateway 内置了十几种常用的有 Path、Method、Header、Query、Cookie、Host、After、Before、Between、RemoteAddr、Weight。它们可以组合只有全部满足才会命中该路由。先看一个组合示例给 orderservice 加时间和路径双重断言- id: order-service uri: lb://orderservice predicates: - Path/order/** - After2024-01-01T17:42:47.78908:00[Asia/Shanghai]After表示请求时间必须晚于指定时间点。如果当前时间早于它请求不会命中这条路由直接 404。把After换成Before当前时间满足就会命中。这个对比很适合用来理解断言“命中/不命中”的边界。Header 断言常用于做灰度或版本区分predicates: - Path/user/** - HeaderX-Request-Id, \d它要求请求头里必须有X-Request-Id且值匹配正则\d。验证curl -i -H X-Request-Id: 12345 http://127.0.0.1:10010/user/1 curl -i -H X-Request-Id: abc http://127.0.0.1:10010/user/1第一条命中第二条因为不匹配正则而 404。Method 断言限制请求方法predicates: - Path/order/** - MethodGET,POSTQuery 断言检查查询参数predicates: - Path/user/** - Queryname, Jack表示必须带?nameJack才命中。RemoteAddr 用于限制来源 IPpredicates: - RemoteAddr192.168.1.1/24Weight 用于灰度分流通常配合两个路由使用- id: user-service-v1 uri: lb://userservice predicates: - Path/user/** - Weightuser-group, 8 - id: user-service-v2 uri: lb://userservice-v2 predicates: - Path/user/** - Weightuser-group, 2这样大约 80% 流量走 v120% 走 v2。断言工厂不需要死记用的时候查官方文档即可关键是理解“多个断言是 AND 关系”任何一个不满足就整体不命中。验证断言是否命中最直接的方式就是看返回码200 是命中404 是没命中503 是命中了但下游不可用。3. 过滤器工厂与全局过滤器可复制配置与执行顺序过滤器工厂GatewayFilter Factory负责在请求转发前后做加工比如加请求头、改路径、限流。它配置在filters下作用于单条路由。默认过滤器default-filters则作用于所有路由。给 userservice 加一个请求头- id: user-service uri: lb://userservice predicates: - Path/user/** filters: - AddRequestHeaderHello, GatewayFilterFactory下游 Controller 里接收这个头GetMapping(/{id}) public User queryById(PathVariable(id) Long id, RequestHeader(value Hello, required false) String hello) { System.out.println(Hello: hello); return userService.queryById(id); }重启后访问控制台会打印Hello: GatewayFilterFactory。如果想让所有路由都带上用默认过滤器spring: cloud: gateway: default-filters: - AddRequestHeaderHello, GatewayFilterFactory常用的还有AddResponseHeader、RewritePath、SetPath、RequestRateLimiter。比如重写路径filters: - RewritePath/api/(?segment.*), /$\{segment}这样/api/user/1会被改写成/user/1再转发。全局过滤器GlobalFilter需要用代码实现作用于所有请求。下面这个做简单的鉴权检查authorization参数是否为adminComponent public class AuthorizeFilter implements GlobalFilter, Ordered { Override public MonoVoid filter(ServerWebExchange exchange, GatewayFilterChain chain) { String authorization exchange.getRequest().getQueryParams().getFirst(authorization); if (admin.equals(authorization)) { return chain.filter(exchange); } exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); return exchange.getResponse().setComplete(); } Override public int getOrder() { return -1; } }验证curl -i http://127.0.0.1:10010/user/1 curl -i http://127.0.0.1:10010/user/1?authorizationadmin第一条返回 401第二条返回 200。执行顺序由Ordered的getOrder()决定值越小越先执行。三类过滤器路由过滤器、DefaultFilter、GlobalFilter最终都会被适配成GatewayFilter合并进同一个过滤器链按 order 排序执行。order 相同时顺序是 DefaultFilter 路由过滤器 GlobalFilter。理解这一点排查“为什么我的过滤器没生效”时就有方向了。4. 跨域 CORS 配置与预检请求验证跨域是浏览器安全策略导致的协议、域名、端口三者任一不同就算跨域。浏览器对非简单请求会先发一个 OPTIONS 预检请求服务器返回合适的 CORS 响应头后浏览器才发真实请求。Gateway 里统一处理跨域比在每个微服务里配更省事。在 gateway 的 application.yml 加spring: cloud: gateway: globalcors: add-to-simple-url-handler-mapping: true corsConfigurations: [/**]: allowedOrigins: - http://localhost:5500 allowedMethods: - GET - POST - DELETE - PUT - OPTIONS allowedHeaders: * allowCredentials: true maxAge: 360000参数清单说明allowedOrigins是允许跨域的源生产环境不要写*配合allowCredentials: true浏览器会拒绝allowedMethods列出允许的方法OPTIONS 必须包含allowedHeaders允许携带的头allowCredentials是否允许带 CookiemaxAge是预检结果缓存时间单位毫秒。前端页面用 axios 请求script srchttps://unpkg.com/axios/dist/axios.min.js/script script axios.get(http://localhost:10010/user/1?authorizationadmin) .then(resp console.log(resp.data)) .catch(err console.log(err)) /script用 Live Server 起在 5500 端口打开 DevTools 的 Network 面板能看到先有一个 OPTIONS 请求返回 200响应头里有Access-Control-Allow-Origin: http://localhost:5500随后才是 GET 请求。如果 OPTIONS 返回 403 或没有 CORS 头检查add-to-simple-url-handler-mapping是否为 true以及 allowedOrigins 是否和页面源完全一致包括端口。5. 常见报错排查401、404、503 与 CORS 预检失败这一节把前面可能遇到的报错集中对照一遍方便你快速定位。401 Unauthorized全局过滤器拦截了。检查请求是否带了authorizationadmin或者过滤器里的判断逻辑是否写反。如果用了 JWT还要确认 token 解析没抛异常。404 Not Found断言没命中。常见原因是 Path 写错、After/Before 时间不满足、Header/Query 条件缺失。排查方法是在 gateway 日志里打开 debuglogging: level: org.springframework.cloud.gateway: debug日志会打印匹配了哪些路由、命中了哪些断言。503 Service Unavailable断言命中了但下游不可用。检查 Nacos 里服务是否注册、服务名是否和lb://后面一致、下游端口是否被占用。如果下游是模型调用类服务还要确认 endpoint 和鉴权配置是否正确。CORS 预检失败OPTIONS 请求被拦截或没返回 CORS 头。确认add-to-simple-url-handler-mapping: trueallowedOrigins 精确匹配allowedMethods 包含 OPTIONS。如果全局过滤器对 OPTIONS 也做鉴权需要放行 OPTIONS 请求否则预检直接 401。OAuth/token 相关报错如果下游调用需要鉴权把鉴权信息统一在网关层注入请求头而不是让每个微服务各自处理。这样下游服务只认网关加的头安全边界更清晰。6. 把下游调用 endpoint 与鉴权配置改到 TaoToken 统一通道前面网关的路由、断言、过滤器、跨域都跑通了接下来把下游对模型服务的调用收敛到统一通道。TaoToken 提供统一的 API 入口官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 。把模型调用的 Base URL、Key、Model ID 三件套配好下游服务就不用各自维护不同的 endpoint。在网关路由里可以把模型调用单独作为一条路由- id: model-service uri: lb://model-service predicates: - Path/ai/** filters: - StripPrefix1下游 model-service 的配置里把模型 endpoint 指向 TaoTokenmodel: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} model-id: your-model-id如果你用的是 Claude Code 这类编码工具配置思路一样Base URL 填 https://taotoken.net/api Key 填申请到的 API KeyModel ID 填对应模型。三件套缺一不可只填 Base URL 不填 Key 会报 401Key 对了但 Model ID 写错会报模型不存在。验证请求curl -i https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d {model:your-model-id,messages:[{role:user,content:ping}]}返回 200 且有 choices 字段说明通道通了。如果报reading choices相关错误通常是响应体不是预期 JSON检查 Base URL 是否多了或少了/v1。如果报 local proxy failed检查网络出口和 DNS。如果报 OAuth 相关错误确认 Key 的类型和权限范围。把 Key 管理放到网关层下游服务通过内部请求头传递避免 Key 散落在各个服务里。需要申请 Key 或查看接入文档可以走 API Keys 页面和接入文档想先验证模型效果用模型对话页面如果是长期编码或 Agent 场景看 Coding Plan。这样网关负责统一入口和鉴权TaoToken 负责统一模型通道职责清晰排查也简单。
返回列表