概要
zuul:springcloud中支持api网关开发的组件。主要功能是路由转发和过滤器。
开发要点:
- 依赖netflix-zuul
- zuul微服务请求url匹配配置
- @EnableZuulProxy启动zuul
- 过滤器开发
1.maven依赖
主要依赖netflix-zuul。zuu也需要注册到eureka服务端中。
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.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.RELEASE</spring-cloud.version>
</properties>
<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>
<!-- zuul网关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
</dependency>
<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>
2.spring配置
注意配置中的微服务请求url匹配配置。
server:
port: 80 # 服务器端口
spring:
application:
name: app-zuul # 微服务名称
eureka:
client:
serviceUrl:
defaultZone: http://localhost:7001/eureka/ # 治理客户端服务域
#zuul网关
zuul:
routes:
serviceproduct: # 产品微服务
path: /product/** # 指定请求匹配url
serviceId: service-product # 指定请求转发的微服务id
serviceuser: # 用户微服务
path: /user/**
serviceId: service-user
#zuul网关超时设置
ribbon:
ConnectTimeout: 1000
ReadTimeout: 2000
3.注解@EnableZuulProxy启动zuul代理
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy // 启动zuul代理
public class AppZuulApplication {
public static void main(String[] args) {
SpringApplication.run(AppZuulApplication.class, args);
}
}
4.zuul过滤器的开发
自定义过滤器需要实现ZuulFilter接口,且可以有多个实现类,按照设定顺序进行过滤。
过滤器需要实现以下四个方法(方法说明参考代码注释):
- shouldFilter()
- run()
- filterType()
- filterOrder()
首先开发第一个过滤器:
import javax.servlet.http.HttpServletRequest;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
/** zuul过滤器pre01 */
@Component
public class ZuulFilterPre01 extends ZuulFilter {
// 是否应该执行该过滤器,如果是false,则不执行该filter
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String id = request.getParameter("id");
// 如果id是空,则不开启过滤,直接放行
return !StringUtils.isEmpty(id);
}
// 执行业务操作,可执行sql,nosql等业务
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String id = request.getParameter("id");
// 如果id=1,则继续执行下一个filter或转发请求
if ("1".equals(id)) {
// 会进行路由,继续执行下一个filter或转发请求
ctx.setSendZuulResponse(true);
ctx.setResponseStatusCode(200);
// 可以把一些值放到ctx中,便于后面的filter获取使用
ctx.set("isOK", true);
} else {
// 不需要进行路由,不会转发请求
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
ctx.set("isOK", false);
// 返回错误内容给客户端
ctx.setResponseBody((ctx.getResponseBody() == null ? "" : ctx.getResponseBody())
+ "{\"error\":\"id mast be 1\"}");
}
return null;
}
// 过滤器类型
// 顺序: pre ->routing -> post ,以上3个顺序出现异常时都可以触发error类型的filter
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
// 同filterType类型中,order值越大,优先级越低
@Override
public int filterOrder() {
return 0;
}
}
开发第二个过滤器:
/** zuul过滤器pre02 */
@Component
public class ZuulFilterPre02 extends ZuulFilter {
// 是否应该执行该过滤器,如果是false,则不执行该filter
@Override
public boolean shouldFilter() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String name = request.getParameter("name");
// 如果name是空,则不开启过滤,直接放行
return !StringUtils.isEmpty(name);
}
// 执行业务操作,可执行sql,nosql等业务
@Override
public Object run() throws ZuulException {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
String name = request.getParameter("name");
// 如果name=zhangsan,则继续执行下一个filter或转发请求
if ("zhangsan".equals(name)) {
// 会进行路由,继续执行下一个filter或转发请求
ctx.setSendZuulResponse(true);
ctx.setResponseStatusCode(200);
// 可以把一些值放到ctx中,便于后面的filter获取使用
ctx.set("isOK", true);
} else {
// 不需要进行路由,不会转发请求
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
ctx.set("isOK", false);
// 返回错误内容给客户端
ctx.setResponseBody((ctx.getResponseBody() == null ? "" : ctx.getResponseBody())
+ "{\"error\":\"name mast be zhangsan\"}");
}
return null;
}
// 过滤器类型
// 顺序: pre ->routing -> post ,以上3个顺序出现异常时都可以触发error类型的filter
@Override
public String filterType() {
return FilterConstants.PRE_TYPE;
}
// 同filterType类型中,order值越大,优先级越低
@Override
public int filterOrder() {
return 1;
}
}
5.测试
启动zuul工程,注册到eureka中。
启动service-product微服务工程(文章SpringBoot学习8.5-feign负载均衡调用微服务中的代码)。
访问http://localhost/product/productRestController/product/5?id=2&name=lisi:
可见,两个过滤器都未转发请求。
访问http://localhost/product/productRestController/product/5?id=1&name=lisi:
访问http://localhost/product/productRestController/product/5?id=1&name=zhangsan:
可见:两个过滤器都给予放行,从微服务获取了数据。
github:https://github.com/zhangyangfei/spring-cloud-learn.git 中的cloud-parent工程。