通过zuul访问某个方法一直Gateway Timeout, status=504 而通过端口直接访问则不会

本文详细记录了解决通过Zuul访问特定方法时出现的504 GatewayTimeout错误的过程。问题源于方法响应时间超过Zuul默认的2秒超时设置。通过调整ribbon配置中的ReadTimeout和ConnectTimeout参数,成功解决了超时问题。

今天遇见一个问题,通过zuul访问一个获取树状数据的方法一直报Gateway Timeout, status=504 ,

{
  "timestamp": "2020-06-29T11:42:00.366+0000",
  "status": 504,
  "error": "Gateway Timeout",
  "message": "com.netflix.zuul.exception.ZuulException: Hystrix Readed time out"
}

发现是被zuul熔断了

com.netflix.zuul.exception.ZuulException: 
    at org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter.findZuulException(SendErrorFilter.java:114) ~[spring-cloud-netflix-zuul-2.0.1.RELEASE.jar:2.0.1.RELEASE]
    at org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter.run(SendErrorFilter.java:76) ~[spring-cloud-netflix-zuul-2.0.1.RELEASE.jar:2.0.1.RELEASE]
    at com.netflix.zuul.ZuulFilter.runFilter(ZuulFilter.java:117) [zuul-core-1.3.1.jar:1.3.1]

而访问其他方法则不会,且通过端口直接访问不会报错。后来发现时zuul没配置响应时间,而我访问的方法响应时间超过了

zuul的默认响应时间2秒。所以配置了一下application.yml就ok了

ribbon:
  ReadTimeout: 120000  #请求处理的超时时间
  ConnectTimeout: 30000  #请求连接的超时时间

<think>我们之前讨论了Eureka与Nginx的结合,现在用户询问的是Eureka和Zuul的使用方法。根据提供的引用,Zuul是Netflix开源的API网关,可以与Eureka服务注册中心集成,实现动态路由、负载均衡、安全验证等功能。 用户需求:了解如何使用Eureka和Zuul。 我们将分步骤讲解: 1. 搭建Eureka Server 2. 创建微服务并注册到Eureka 3. 搭建Zuul网关 4. 配置Zuul路由规则 5. 高级功能(如过滤器、Swagger集成) 注意:引用中提到了Zuul可以集成Eureka,并且能够进行请求拦截(如token验证)以及Swagger的聚合配置。 --- ### 一、Eureka Server 搭建 1. **创建Spring Boot项目** 使用Spring Initializr(https://start.spring.io/)创建项目,选择依赖: - Eureka Server 2. **配置application.yml** ```yaml server: port: 8761 eureka: client: register-with-eureka: false # 自身不注册到其他Eureka fetch-registry: false # 不获取其他Eureka的服务列表 ``` 3. **启用Eureka Server** 在启动类添加注解: ```java @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } } ``` 4. **启动并访问** `http://localhost:8761` 进入Eureka控制台。 --- ### 二、微服务注册到Eureka 1. **微服务配置** ```yaml spring: application: name: user-service # 服务名称 eureka: client: service-url: defaultZone: http://localhost:8761/eureka # Eureka地址 ``` 2. **启用服务发现** 启动类添加注解(可选,如果使用RestTemplate或Feign则需要): ```java @SpringBootApplication @EnableDiscoveryClient // 或 @EnableEurekaClient public class UserServiceApplication { ... } ``` --- ### 三、Zuul网关搭建 1. **创建Zuul项目** 选择依赖: - Zuul - Eureka Discovery Client(用于从Eureka获取服务) 2. **配置application.yml** ```yaml server: port: 8080 spring: application: name: zuul-gateway eureka: client: service-url: defaultZone: http://localhost:8761/eureka # 注册到Eureka zuul: routes: user-service: /user/** # 将/user/**的请求路由到user-service order-service: /order/** # 将/order/**的请求路由到order-service ``` 3. **启用Zuul代理** 启动类添加注解: ```java @SpringBootApplication @EnableZuulProxy public class ZuulGatewayApplication { public static void main(String[] args) { SpringApplication.run(ZuulGatewayApplication.class, args); } } ``` --- ### 四、动态路由与负载均衡 - **动态路由**:Zuul自动从Eureka获取服务实例列表,无需硬编码IP。 - **负载均衡**:Zuul内置Ribbon,默认轮询策略。 > 访问示例: > `http://localhost:8080/user/1` → 自动转发到`user-service`的某个实例的`/1`接口。 --- ### 五、过滤器实现(Token验证示例) Zuul的核心功能之一是通过过滤器(Filter)实现请求拦截。 1. **创建Pre过滤器** ```java public class TokenFilter extends ZuulFilter { @Override public String filterType() { return "pre"; // 前置过滤器 } @Override public int filterOrder() { return 0; } @Override public boolean shouldFilter() { return true; // 始终执行 } @Override public Object run() throws ZuulException { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); // 检查token参数 String token = request.getParameter("token"); if (token == null || !token.equals("valid_token")) { ctx.setSendZuulResponse(false); // 拦截请求 ctx.setResponseStatusCode(401); ctx.setResponseBody("Access denied: token is invalid"); } return null; } } ``` 2. **注册过滤器** 在启动类添加: ```java @Bean public TokenFilter tokenFilter() { return new TokenFilter(); } ``` > 此时所有请求必须携带`token=valid_token`参数,否则返回401[^1]。 --- ### 六、Swagger文档聚合 当微服务使用Swagger时,Zuul可聚合所有服务的Swagger文档(引用[3]示例)。 1. **添加依赖** ```xml <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> ``` 2. **配置Swagger资源提供者** ```java @Component @Primary public class DocumentationConfig implements SwaggerResourcesProvider { @Override public List<SwaggerResource> get() { List<SwaggerResource> resources = new ArrayList<>(); // 从Eureka获取的服务列表动态生成,此处简化 resources.add(swaggerResource("用户服务", "/user-service/v2/api-docs", "2.0")); resources.add(swaggerResource("订单服务", "/order-service/v2/api-docs", "2.0")); return resources; } private SwaggerResource swaggerResource(String name, String location, String version) { SwaggerResource resource = new SwaggerResource(); resource.setName(name); resource.setLocation(location); resource.setSwaggerVersion(version); return resource; } } ``` 3. **访问聚合文档** `http://localhost:8080/swagger-ui.html` --- ### 七、常见问题 1. **路由配置不生效** - 检查服务名是否与Eureka注册名一致(大小写敏感)。 - 确认Zuul已连接到Eureka(查看日志)。 2. **过滤器不执行** - 确保过滤器被Spring容器管理(`@Component`或`@Bean`)。 - 检查`filterType()`返回值是否正确(pre/route/post/error)。 3. **超时问题** 调整Zuul的超时设置: ```yaml zuul: host: connect-timeout-millis: 5000 socket-timeout-millis: 10000 ``` --- ### 八、备选方案:Spring Cloud Gateway > Zuul 1.x已进入维护模式,建议新项目使用Spring Cloud Gateway(基于WebFlux,支持异步非阻塞)。 | 特性 | Zuul 1.x | Spring Cloud Gateway | |--------------|---------------|----------------------| | 性能 | 阻塞IO | 非阻塞异步 | | 依赖 | Servlet | Netty/WebFlux | | 功能扩展 | Filter | Predicate/Filter | | 学习曲线 | 低 | 中高 | 迁移示例: ```yaml spring: cloud: gateway: routes: - id: user-service uri: lb://user-service # lb表示从注册中心负载均衡 predicates: - Path=/user/** ``` --- ### 总结流程图 ```mermaid graph LR 客户端 -->|请求| Zuul网关 Zuul网关 -->|动态路由| Eureka注册中心 Eureka注册中心 -->|返回服务实例| Zuul网关 Zuul网关 -->|转发请求| 微服务实例 微服务实例 -->|返回响应| Zuul网关 Zuul网关 -->|返回客户端| 客户端 ``` §§相关问题§§ 1. ZuulSpring Cloud Gateway的主要区别是什么? 2. 如何在Zuul中实现限流? 3. Eureka服务注册发现的工作原理?</think>### Eureka 与 Zuul 结合实现微服务调用指南 Eureka 是服务注册与发现中心,Zuul 是 API 网关,两者结合可实现动态路由、负载均衡和安全控制。以下是完整实现方案: --- #### 一、核心架构 ```mermaid graph LR A[客户端] --> B(Zuul网关) B --> C{Eureka注册中心} C --> D[微服务A] C --> E[微服务B] ``` 1. **服务注册**:微服务启动时向 Eureka 注册信息(IP、端口) 2. **动态路由**:Zuul 从 Eureka 获取服务列表实现请求路由 3. **统一入口**:所有外部请求通过 Zuul 网关访问后端服务[^1] --- #### 二、环境搭建步骤 ##### 1. 创建 Eureka Server **依赖配置** (pom.xml): ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> ``` **启动类配置**: ```java @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } } ``` **配置文件** (application.yml): ```yaml server: port: 8761 eureka: client: register-with-eureka: false # 不注册自身 fetch-registry: false # 不获取注册表 ``` --- ##### 2. 创建 Zuul 网关 **依赖配置** (pom.xml): ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> ``` **启动类配置**: ```java @SpringBootApplication @EnableZuulProxy public class ZuulGatewayApplication { public static void main(String[] args) { SpringApplication.run(ZuulGatewayApplication.class, args); } } ``` **配置文件** (application.yml): ```yaml server: port: 8080 spring: application: name: zuul-gateway eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ # 连接Eureka[^2] zuul: routes: user-service: /users/** # 用户服务路由规则 order-service: /orders/** # 订单服务路由规则 ``` --- ##### 3. 创建微服务(以用户服务为例) **配置文件** (application.yml): ```yaml server: port: 8081 spring: application: name: user-service # 服务名称必须唯一 eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ # 注册到Eureka ``` --- #### 三、核心功能实现 ##### 1. 动态路由与负载均衡 Zuul 自动从 Eureka 获取服务实例并实现负载均衡: ```java // 通过服务名访问其他微服务 @RestController public class OrderController { @GetMapping("/user-info") public String getUserInfo() { // 直接使用服务名访问 return restTemplate.getForObject( "http://user-service/users/123", // 服务名而非IP String.class ); } } ``` ##### 2. 请求过滤(Token验证) ```java public class TokenFilter extends ZuulFilter { @Override public String filterType() { return "pre"; // 前置过滤器 } @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); // 检查Token参数 if (request.getParameter("token") == null) { ctx.setSendZuulResponse(false); // 拦截请求 ctx.setResponseStatusCode(401); ctx.setResponseBody("Access denied: token is required"); } return null; } } ``` 注册过滤器:`@Bean public TokenFilter tokenFilter() { return new TokenFilter(); }`[^1] --- ##### 3. Swagger 文档聚合 ```java @Primary @Component public class SwaggerConfig implements SwaggerResourcesProvider { @Override public List<SwaggerResource> get() { List<SwaggerResource> resources = new ArrayList<>(); // 添加用户服务文档 resources.add(swaggerResource("用户服务", "/user-service/v2/api-docs", "2.0")); // 添加订单服务文档 resources.add(swaggerResource("订单服务", "/order-service/v2/api-docs", "2.0")); return resources; } private SwaggerResource swaggerResource(String name, String location, String version) { SwaggerResource resource = new SwaggerResource(); resource.setName(name); resource.setLocation(location); resource.setSwaggerVersion(version); return resource; } } ``` 访问统一文档:`http://zuul-host:port/swagger-ui.html`[^3] --- #### 四、高级配置 ##### 1. 路由重写 ```yaml zuul: routes: user-service: path: /api/users/** serviceId: user-service stripPrefix: false # 保留完整路径 ``` ##### 2. 熔断降级 ```java @Bean public ZuulFallbackProvider userServiceFallback() { return new ZuulFallbackProvider() { @Override public String getRoute() { return "user-service"; // 指定服务 } @Override public ClientHttpResponse fallbackResponse() { return new ClientHttpResponse() { @Override public HttpStatus getStatusCode() { return HttpStatus.SERVICE_UNAVAILABLE; } @Override public String getStatusText() { return "Service Unavailable"; } // 自定义降级响应体 @Override public InputStream getBody() { return new ByteArrayInputStream("用户服务暂不可用".getBytes()); } }; } }; } ``` ##### 3. 请求限流 ```java @Bean public RateLimiter zuulRateLimiter() { return new RateLimiter() { @Override public boolean isAllowed(String route, String key) { // 每秒钟允许10个请求 return rateLimiter.tryAcquire(10, TimeUnit.SECONDS); } }; } ``` --- #### 五、最佳实践 1. **命名规范**: - 服务名使用小写(`user-service` 而非 `UserService`) - 路径前缀与服务名保持一致 2. **安全建议**: ```yaml zuul: sensitive-headers: Cookie,Set-Cookie # 屏蔽敏感头信息 add-proxy-headers: true ``` 3. **性能优化**: ```yaml zuul: host: max-per-route-connections: 20 # 单路由最大连接数 max-total-connections: 200 # 总连接数 socket-timeout-millis: 10000 # 超时设置 ``` --- #### 六、常见问题排查 | 问题现象 | 解决方案 | |---------|----------| | 服务未注册到Eureka | 检查`spring.application.name`和`defaultZone`配置 | | Zuul路由404错误 | 确认服务名与`zuul.routes`配置匹配 | | Swagger文档加载失败 | 检查`@Primary`注解和资源路径配置[^3] | | 过滤器不生效 | 确认`filterType()`返回正确类型(pre/post等) | > **注意**:Zuul 1.x 已进入维护模式,新项目建议使用Spring Cloud Gateway [^1]: Zuul 提供请求拦截和预处理能力 [^2]: Zuul 通过 Eureka 客户端获取服务注册信息 [^3]: 通过自定义 SwaggerResourcesProvider 实现文档聚合
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值