springcloud 路由网关 - zuul

xiaoxiao2025-04-20  19

spring cloud微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(zuul、ngnix),再到达服务网关(zuul集群),然后再到具体的服务。服务统一注册到高可用的服务注册中心集群,服务的所有配置文件由配置服务管理,配置服务的配置文件放在git仓库,方便开发人员随时改变配置。

简介

zuul的主要功能是路由转发和过滤器。路由功能是微服务的一部分。

zuul有以下功能:

(1)Authentication(认证)

(2)Insights

(3)Stress Testing(压力测试)

(4)Canary Testing(金丝雀测试)

(5)Dynamic Routing(动态路由)

(6)Service Migration(服务迁移)

(7)Load Shedding(负载调度)

(8)Security(案例)

(9)Static Response handling(静态响应处理)

(10)Active traffic management

zuul中默认实现的filter

类型顺序过滤器功能pre-3ServletDetectionFilter标记处理Servlet的类型pre-2Servlet3oWrapperFilter包装HttpServletRequests请求pre-1FormBodyWrapperFilter包装请求体route1DebugFilter标记调试标志route5PreDecorationFilter处理请求上下文供后续使用route10RibbonRoutingFilterserviceId请求转发route100SimpleHostRoutingFilterurl请求转发route500SendForwardFilterforward请求转发post0SendErrorFilter处理有错误的请求响应pos1000SendResponseFilter处理正常的请求响应

可以在application.yml中配置需要禁用的filter,格式 :

zuul: FormBodyWrapperFilter: pre: disable: true

自定义Filter

实现自定义Filter,需要继承ZuulFilter的类,并覆盖其中的4个方法。

public class MyFilter extends ZuulFilter { @Override String filterType() { return "pre"; //定义filter的类型,有pre、route、post、error四种 } @Override int filterOrder() { return 10; //定义filter的顺序,数字越小表示顺序越高,越先执行 } @Override boolean shouldFilter() { return true; //表示是否需要执行该filter,true表示执行,false表示不执行 } @Override Object run() { return null; //filter需要执行的具体操作 } }

实践

1、在原有的工程上,创建一个的新的工程service-zuul

2、其pom.xml文件如下

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.forezp</groupId> <artifactId>service-zuul</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>service-zuul</name> <description>Demo project for Spring Boot</description> <parent> <groupId>com.forezp</groupId> <artifactId>sc-f-chapter5</artifactId> <version>0.0.1-SNAPSHOT</version> </parent> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> </dependencies> </project>

3、在其入口application类加上注解@EnableZuulProxy,开启zuul的功能

@SpringBootApplication @EnableZuulProxy @EnableEurekaClient @EnableDiscoveryClient public class ServiceZuulApplication { public static void main(String[] args) { SpringApplication.run( ServiceZuulApplication.class, args ); } }

4、加上配置文件application.yml加上以下配置代码

eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ server: port: 8769 spring: application: name: service-zuul zuul: routes: api-a: path: /api-a/** serviceId: service-ribbon api-b: path: /api-b/** serviceId: service-feign

服务过滤

zuul不仅只是路由,并且还能过滤,做一些安全验证。

@Component public class MyFilter extends ZuulFilter { private static Logger log = LoggerFactory.getLogger(MyFilter.class); @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 0; } @Override public boolean shouldFilter() { return true; } @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString())); Object accessToken = request.getParameter("token"); if(accessToken == null) { log.warn("token is empty"); ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(401); try { ctx.getResponse().getWriter().write("token is empty"); }catch (Exception e){} return null; } log.info("ok"); return null; } }

1、fiterType: 返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤喊器类型,具体如下:

(1)pre: 路由之前

我们可以利用这种过滤器实现身份验证、在集群中执行请求的微服务,记录调用信息等。

(2)routing:路由之时

(3)post:路由之后

(4)error:发送错误调用

2、filterOrder: 过滤顺序

3、shouldFilter:这里可以写逻辑判断,是否要过滤。

4、run:过滤器的具体逻辑

5、访问http://localhost:8769/api-a/hi?name=xxx

6、访问http://localhost:8769/api-a/hi?name=xxx&token=22

zuul的高可用

因为外部请求到后端服务的流量都会经过zuul,故而在生产环境中,我们一般都需要部署高可用的zuul以避免单点故障。

1、zuul客户端也注册到了eureka server上

这种情况下,zuul的高可用非常简单,只需将多个zuul节点注册到eureka server上,就可实现zuul的高可用。此时,zuul的高可用与其他微服务的高可用没什么区别。

当zuul客户端也注册到eureka server上时,只需部署多个zuul节点即可实现其高可用。zuul客户端会自动从eureka server中查询zuul server的列表,并使用ribbon负载均衡的请求zuul集群。

2、zuul客户端未注册到eureka server上

现实中,这种场景往往更常见,例如,zuul客户端是一个手机app,我们不可能让所有手机端都注册到eureka server上,这种情况下,我们可借助一个额外的负载均衡器来实现zuul的高可用,例如nginx、haproxy、f5等。

问题

1、跨域访问

正常情况下,跨域是这样的:

微服务配置跨域+zuul不配置=有跨域问题

微服务配置+zuul配置=有跨域问题

微服务不配置+zuul不配置=有跨域问题

微服务不配置+zuul配置=ok

(1)zuul配置忽略头部信息

zuul: ignored-headers: Access-Control-Allow-Origin,H-APP-Id,Token,APPToken

(2)跨域配置

@Component @Configuration public class GateWayCorsConfig { @Bean public CorsFilter corsFilter() { final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); final CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowCredentials(true);//允许cookie跨域 //允许访问的头信息,*表示全部 corsConfiguration.addAllowedHeader("*"); //允许向服务器提交请求的URI,*表示全部允许, corsConfiguration.addAllowedOrigin("*"); //允许提交请求的方法,*表示全部允许 corsConfiguration.addAllowedMethod("*"); corsConfiguration.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了 source.registerCorsConfiguration("/**", corsConfiguration); return new CorsFilter(source); } }

只要网关配置好了,底下的服务不需要配置。

2、中文乱码

解决办法:

(1)注意编码,全站api和前端全部使用utf-8,zuul中强制编码为utf-8.

spring: http: encoding: charset: UTF-8 enabled: true force: true

3、post json中获取参数token

RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); String method = request.getMethod(); String token = null; if(method.equalsIgnoreCase("GET")){ token = request.getParameter("token"); }else if(method.equalsIgnoreCase("POST")){ try { InputStream inputStream = request.getInputStream(); String body = StreamUtils.copyToString(inputStream, Charset.forName("UTF-8")); JSONObject jsonObject = JSONObject.parseObject(body); token = jsonObject.getString("token"); }catch (Exception e){ e.printStackTrace(); token = null; } }

配置

1、zuul.max.host.connections

这个配置已经被两个配置项替换: zuul.host.maxTotalConnections和zuul.host.maxPerRouteConnections,默认是200,另一个是20.

2、zuul timeout

如果使用service discovery,可以通过ribbon.ReadTimeout(默认5s)和ribbon.ConnectTimeout(默认2s)设置。

如果通过URL,可以通过zuul.host.connect-timeout-millis和zuul.host.socket-timeot-millis设置。

 

转载请注明原文地址: https://www.6miu.com/read-5028723.html

最新回复(0)