SpringCloud学习(五):Zuul 路由过滤/网关
菜鸟学渣接触spring cloud 系列...
公司也上微服务了,再不学习下就凉了,所以来踩坑吧...
版本:
spring-boot: 2.0
spring-cloud: Finchley.SR1
已有项目:
[eureka-server] # 注册中心 port 8761
[eureka-client-one] # 微服务1 port 8501
[eureka-client-two] # 微服务2 port 8502
[eureka-client-turbine] # 断路监控 port 8503
能上图绝不BB:
添加网关后,所有微服务API都通过ZUUL访问,zuul根据url分发到各个微服务实例
spring-cloud-gateway是Spring自己撸的网关,和netflx-zuul性质一样,后面也去学习一下.
一、Zuul网关 [eureka-client-zuul]
新建项目[eureka-client-zuul]
引入依赖 spring-cloud-starter-netflix-zuul
<?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.renzku</groupId> <artifactId>eureka-client-zuul</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>eureka-client-zuul</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Finchley.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
配置文件 application.yml
server: port: 8601 spring: application: name: eureka-client-zuul eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/ # 动态路由后面研究 # 默认引入eureka后不手动配置,会自动为每个服务都创建一个默认路由规则: 访问路径的前缀为serviceId配置的服务名称,这里修改下 zuul: routes: clientOne: path: /client-one/** serviceId: eureka-client-one clientTwo: path: /client-two/** serviceId: eureka-client-two # url: http://localhost:8502/
启动类 EurekaClientZuulApplication.java
@SpringBootApplication @EnableEurekaClient @EnableZuulProxy public class EurekaClientZuulApplication { public static void main(String[] args) { SpringApplication.run(EurekaClientZuulApplication.class, args); } }
目录结构
访问 http://localhost:8601/client-one 和 http://localhost:8601/client-two
zuul根据url分别访问了微服务[eureka-client-one]和[eureka-client-two]
二、ZuulFilter过滤
过滤器有4中:
pre: 该类型的filters在Request routing到源web-service之前执行。用来实现Authentication、选择源服务地址等
routing:该类型的filters用于把Request routing到源web-service,源web-service是实现业务逻辑的服务。这里使用HttpClient请求web-service。
post:该类型的filters在ROUTING返回Response后执行。用来实现对Response结果进行修改,收集统计数据以及把Response传输会客户端。
error:上面三个过程中任何一个出现错误都交由ERROR类型的filters进行处理。
顺序:
来源: https://blog.csdn.net/tianyaleixiaowu/article/details/77893822
‘pre' 过滤器 ZuulRequestFilter.java
public class ZuulRequestFilter extends ZuulFilter { public int filterOrder() { // filter 顺序 return 5 - 1; } public String filterType() {
// filter 类型 return "pre"; } @Override public boolean shouldFilter() {
// filter 是否生效,这里一般根据请求头中的header灵活设置 return true; } public Object run() { RequestContext ctx = getCurrentContext(); // 添加个头信息 转发到其他微服务的请求头中会带上 “requestFilterParam” ctx.addZuulRequestHeader("requestFilterParam", "here is RequestFilter!"); return null; } }
'post'过滤器 ZuulResponseFilter.java
public class ZuulResponseFilter extends ZuulFilter { public String filterType() { return "post"; } public int filterOrder() { return 999; } public boolean shouldFilter() { return true; } public Object run() { RequestContext context = RequestContext.getCurrentContext(); HttpServletResponse servletResponse = context.getResponse(); // 添加个头信息 最后返回数据的头信息header中会带上 “responseFilterParam” servletResponse.addHeader("responseFilterParam", "here is ResponseFilter!"); return null; } }
启动类加入Filter使生效
@SpringBootApplication @EnableEurekaClient @EnableZuulProxy public class EurekaClientZuulApplication { @Bean public ZuulRequestFilter requestFilter(){ return new ZuulRequestFilter(); } @Bean public ZuulResponseFilter responseFilter(){ return new ZuulResponseFilter(); } public static void main(String[] args) { SpringApplication.run(EurekaClientZuulApplication.class, args); } }
测试 ZuulRequestFilter 和 ZuulResponseFilter:
[eureka-client-one]中添加个Rest API: “/zuul/test"
@RestController public class HelloWorld { @RequestMapping("/") @HystrixCommand(fallbackMethod = "someBoom") public String home(){ int a = 0, c = 1; int d = c/a; // 抛出异常触发 return "hello world"; } public String someBoom(){ return "wokao, 魂淡"; } @RequestMapping("/zuul/test") public String zuulTest(@RequestHeader String requestFilterParam){ return "requestFilterParam: " + requestFilterParam + " .--client one"; } }
通过网关访问 http://localhost:8601/client-one/zuul/test
可以看到 2个过滤器都生效了..
三、Zuul 断路器
如果某个微服务炸了,zuul可以实现断路器的功能
从依赖来看,是基于hystrix
新增fallback类 MyZuulFallbackProvider.java
/** * 默认回退 */ public class MyZuulFallbackProvider implements FallbackProvider{ /** * 为那个微服务提供回退: *\null为 所有 * @return 这里不是eureka的serviceId,而是zuul.routes下的值,比如为[eureka-client-one]断路,则return "clientOne" */ @Override public String getRoute() { return null; } @Override public ClientHttpResponse fallbackResponse(String route, Throwable cause) { return new ClientHttpResponse() { @Override public HttpStatus getStatusCode() throws IOException { return HttpStatus.OK; } @Override public int getRawStatusCode() throws IOException { return 200; } @Override public String getStatusText() throws IOException { return "OK"; } @Override public void close() { } @Override public InputStream getBody() throws IOException { return new ByteArrayInputStream("zuul fallback".getBytes()); // 回退信息 } @Override public HttpHeaders getHeaders() { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; } }; } }
启动类加入使其生效
@SpringBootApplication @EnableEurekaClient @EnableZuulProxy public class EurekaClientZuulApplication { @Bean public ZuulRequestFilter requestFilter(){ return new ZuulRequestFilter(); } @Bean public ZuulResponseFilter responseFilter(){ return new ZuulResponseFilter(); } @Bean public FallbackProvider fallbackProvider(){ return new MyZuulFallbackProvider(); } public static void main(String[] args) { SpringApplication.run(EurekaClientZuulApplication.class, args); } }
现在把[eureka-client-one]关闭,zuul路由访问必定报错,触发fallback
访问 http://localhost:8601/client-one/zuul/test