前面几篇介绍了spring cloud中比较核心的几个模块,eureka,ribbon,hystrix,feign,config,接下来我们研究下spring cloud另一模块zuul,API网关。
根据之前的所提到的spring cloud功能,我们能够基于eureka建立服务注册和发现,ribbon、feign、hystrix建立客户端调用的负载均衡和熔断机制,spring cloud config建立统一的配置中心。上述这种多实例部署后,通过前置负载均衡器如 F5,NGINX等
但是,这样架构有一个问题在于,上线之后服务众多,当增加了服务实例,或者实例的请求路径发生了更改,运维人员需要手动去维护nginx和F5这些配置,另外多服务实例中,很多模块会公用到一些功能,如SSO,权限校验等,因此API网关的概念因此诞生,spring cloud提供了zuul API网关路由。
下面进行spring cloud zuul的入门研究,建立service-zuul模块,pom依赖如下:
<?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>spring-cloud-test-001</artifactId>
<groupId>com.leo.test</groupId>
<version>1.0.0-snapshot</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>service-zuul-001</artifactId>
<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>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
模块配置application.yml如下:
spring:
application:
name:
service-zuul-001 #配置应用名称
server:
port:
9010 #配置端口号
eureka:
client:
service-url:
defaultZone:
http://leo-node:8081/eureka # eureka配置
zuul:
routes:
providerapi:
path: /provider/**
serviceId: service-provider-001
stripPrefix: false
consumerapi:
path: /consumer/**
serviceId: service-consumer-ribbon-001
stripPrefix: false
启动类配置如下:
import com.leo.test.spring.cloud.test.service.zuul.filter.MyZuulFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
@EnableZuulProxy
@EnableEurekaClient
public class ServiceZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceZuulApplication.class);
}
@Bean
public MyZuulFilter getZuulFilter(){
return new MyZuulFilter();
}
}
实现自己的ZuulFilter逻辑:
public class MyZuulFilter extends ZuulFilter {
/**
* 返回四种类型:
* pre pre-routing过滤,路由前过滤
* routing 在路由请求时被调用
* post routing和error过滤器之后被调用
* error 处理请求发生错误的时候调用
* @return
*/
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
/**
* 该过滤器是否需要执行
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
Object token = request.getParameter("token");
if(token == null ){
System.out.println("token is empty");
//过滤该请求,不进行路由
ctx.setSendZuulResponse(false);
//返回对应http status状态码
ctx.setResponseStatusCode(401);
//设置返回的内容
ctx.setResponseBody("{'error':'token is empty'}");
return null;
}
System.out.println("got token,continuing ... ");
return null;
}
}
启动eureka-server和色弱Vic的-provider,然后启动service-zuul,访问http://localhost:9010/provider/sayHello
没有token参数的时候,返回的预期的错误,我们增加token参数:
访问正常。
zuul中有四种过滤器:pre,routing,post,error
首先是经过pre过滤器,进行正式请求前的一些前置处理,routing就是路由转发阶段,当该阶段完成,请求完成,然后进入post阶段,这个时候我们不仅可以拿到请求信息,也能够获取请求的响应结果信息。
上面这三个阶段任一阶段发生错误都会触发,但是最后还是会流向post过滤器,通过post过滤器返回相应给客户端。
zuul请求流程: