一、简介
Zuul是Netfliex公司开源的为微服务提供服务路由和过滤的一个组件,作为网关的一种选择方案。Spring Cloud 团队将其集成进来形成Spring Cloud zuul组件。
Spring Cloud Zuul 内置 zuul proxy 代理服务器
二、路由
在application配置文件中,如果serviceId和route名称相同 配置可以如下
zuul: ignoredServices: '*' routes: users: /myusers/**或者
zuul: routes: users: path: /myusers/** serviceId: users_service
或者 提供一个具体的物理地址
zuul: routes: users: path: /myusers/** url: http://example.com/users_service匹配规则要符合ant风格。我们可以通过代码自定义匹配规则
@Bean public PatternServiceRouteMapper serviceRouteMapper() { return new PatternServiceRouteMapper( "(?<name>^.+)-(?<version>v.+$)", "${version}/${name}"); }
我们可以通过zuul.prefix 增加路径前缀,在路由前改前缀会被删除,如果个别服务需要不删除则需要在route 下 设置zuul.stripPrefix=false
zuul: routes: users: path: /myusers/** stripPrefix: false
三、过滤
zuul过滤器有四种类型分别非 pre,route ,post,error ,代表路由前,路由时,路由完毕,发生错误时的过滤器。
自定义ZuulFilter需要继承ZuulFilter ,
public class AddResponseHeaderFilter extends ZuulFilter { @Override public String filterType() { return POST_TYPE; } @Override public int filterOrder() { return SEND_RESPONSE_FILTER_ORDER - 1; } @Override public boolean shouldFilter() { return true; } @Override public Object run() { RequestContext context = RequestContext.getCurrentContext(); HttpServletResponse servletResponse = context.getResponse(); servletResponse.addHeader("X-Foo", UUID.randomUUID().toString()); return null; } }
该过滤器在路由结束后会调用,增加了一个响应头。
四、使用
创建spring boot 项目 添加依赖spring-cloud-starter-zuul ,我们使用eureka 作为服务注册中心。添加eureka依赖
spring-cloud-starter-eureka
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency>
创建程序入口类,在这个类中注入了一个zuulFilter
@SpringBootApplication @EnableZuulProxy @EnableEurekaClient public class ZuulApplication { public static void main(String[] args) { SpringApplication.run(ZuulApplication.class, args); } @Bean MyZuulFilter zuulFilter(){ return new MyZuulFilter(); } }
创建一个zuul过滤器类MyZuulFilter
public class MyZuulFilter extends ZuulFilter { @Override public String filterType() { return POST_TYPE; //过滤器类型 有pre route post error } @Override public int filterOrder() { return 1; //过滤器顺序 越小越优先 } @Override public boolean shouldFilter() { return true; //是否过滤 } @Override public Object run() { RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest(); String servletPath = request.getServletPath(); //zuul 对所有 /** forward转发 到本地的 的请求进行重定向 到百度 if (servletPath.lastIndexOf("/")==0){ HttpServletResponse response = currentContext.getResponse(); try { response.sendRedirect("http://www.baidu.com"); } catch (IOException e) { e.printStackTrace(); } return null; }HttpServletResponse response = currentContext.getResponse(); Cookie cookie = new Cookie("time-respose", "nowtamstamp" + System.currentTimeMillis()); response.addCookie(cookie); return null; }}
在这个类中,我们给响应头增加了一个cookie。
配置文件 application.yml
spring: application: name: zuul server: port: 2000 zuul: ignoredPatterns: /**/admin/** #忽略路径含有admin的请求 sensitiveHeaders: Cookie,Set-Cookie,Authorization #对于外部消费者 忽律这些敏感头 #ignoredHeaders: #忽略的头部 routes: hello: path: /hello/** serviceId: eureka-client-consumer #serviceId 在虚拟地址 ribbon 通过serviceId查找服务列表 这里重eureka中获取 # url: http://localhost:8001 #物理地址
r: path: /** url: forward:/ ## /** 转发到本地 / 服务prefix: /api #增加前缀eureka: client: service-url: defaultZone: http://localhost:8761/eureka/ instance: lease-renewal-interval-in-seconds: 3 #3秒钟一次心跳 lease-expiration-duration-in-seconds: 5 #5秒超时
在这个配置文件中定义了一个route. 将/hello/** 路由到eureka-client-consumer服务。
/** 转发到 zuul 的/服务下。
zuul 对本地服务/** 过滤进行重定向:
@Override public Object run() { RequestContext currentContext = RequestContext.getCurrentContext(); HttpServletRequest request = currentContext.getRequest(); String servletPath = request.getServletPath(); //zuul 对所有 /** forward转发 到本地的 的请求进行重定向 到百度 if (servletPath.lastIndexOf("/")==0){ HttpServletResponse response = currentContext.getResponse(); try { response.sendRedirect("http://www.baidu.com"); } catch (IOException e) { e.printStackTrace(); } return null; } return null; }
启动服务。 访问localhost:2000/api/hello/hello 成功返回。 并且响应头中增加了一个cookie .