zuul简介
Zuul的主要功能是路由和过滤,路由是微服务架构不可或缺的一部分,例如将/api/user转发到到user服务,/api/shop转发到到shop服务。 Zuul是Netflix研发的基于JVM路由器和服务器端的负载均衡器
zuul的用途:
- Authentication
- Insights
- Stress Testing
- Canary Testing
- Dynamic Routing
- Service Migration
- Load Shedding
- Security
- Static Response handling
- Active/Active traffic management
路由
- 在父工程下创建一个工程
<?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">
<parent>
<artifactId>springcloud-demo</artifactId>
<groupId>demo.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>zuul-service</artifactId>
<name>zuul-service</name>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- zuul依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependencies>
</project>
- 开启zuul功能
@SpringBootApplication
@EnableDiscoveryClient
//开启zuul
@EnableZuulProxy
public class ZuulServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulServiceApplication.class, args);
}
}
- 修改application.yml
server:
port: 8810
spring:
application:
#服务名称
name: zuul-service
eureka:
client:
#是否将自己注册到Eureka服务中
register-with-eureka: true
#是否从Eureka服务中获取注册信息
fetch-registry: true
#Eureka注册中心的地址,多个注册中心用,隔开
serviceUrl:
defaultZone: http://localhost:8761/eureka/
zuul:
routes:
#将/baidu/**的请求转发到https://www.baidu.com
baidu:
path: /baidu/**
url: https://www.baidu.com
#将/ribbon/**的请求转发到ribbon-consumer的服务
ribbon-api:
path: /ribbon/**
service-id: ribbon-consumer
feign-api:
path: /feign/**
service-id: feign-consumer
-
测试
依次启动eureka-server, eureka-service,ribbon-consumer, feign-consumer,zuul-service
浏览器访问http://localhost:8810/ribbon/testport:8763
浏览器访问http://localhost:8810/feign/test
port:8763
过滤
- 创建过滤器
@Component
public class MyFilter extends ZuulFilter {
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
/**
* 获取请求uri,如果uri以feign开头则拦截,执行过滤
*/
HttpServletRequest request = RequestContext.getCurrentContext().getRequest();
String requestURI = request.getRequestURI();
if(requestURI.startsWith("/feign/")){
return true;
}
return false;
}
@Override
public Object run() throws ZuulException {
/**
* 获取请求中是否包含token信息,如果token信息为空,则返回错误信息
*/
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
String token = request.getParameter("token");
if(token == null || token.isEmpty()){
//不进行路由
currentContext.setSendZuulResponse(false);
//返回的状态码
currentContext.setResponseStatusCode(400);
//返回的信息
currentContext.setResponseBody("token is not empty");
return null;
}
return null;
}
}
filterType: 过滤器类型的生命周期
- pre:请求路由之前
- routing:请求路由到微服务时
- post:请求路由到微服务后
- error:发生错误时
filterOrder:过滤器的优先级,越小优先级越高
shouldFilter:过滤的条件,true为过滤,false为不过滤
run:执行过滤的具体逻辑
-
测试
再次访问http://localhost:8810/feign/testtoken is not empty
请求参数中携带token访问http://localhost:8810/feign/test?token=a
port:8763
路由熔断
当Zuul中给定路由的服务出现错误时,可以通过创建类型为FallbackProvider的bean来提供响应
- 创建熔断类
@Component
public class MyFallback implements FallbackProvider {
//指定处理的服务,*代表所有服务
@Override
public String getRoute() {
return "ribbon-consumer";
}
@Override
public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
@Override
public int getRawStatusCode() throws IOException {
return 500;
}
@Override
public String getStatusText() throws IOException {
return "Internal Server Error";
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream("服务器异常".getBytes());
}
@Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}
- 测试
关闭ribbon-consumer服务,再次访问http://localhost:8810/ribbon/test服务器异常
作者公众号