SpringCloud 2.0 之 zuul
官网:https://cloud.spring.io/spring-cloud-netflix/multi/multi__router_and_filter_zuul.html
zuul 介绍
Zuul是Netflix的基于JVM的微服务网关, 介于服务端与客户端的中间层,所有外部服务请求都会先经过微服务网关, 他可以与Eureka, Ribbon, Hystrix配合使用.
微服务网关好处:
1: 客户只能跟微服务网关进行交互,无需调用特定微服务接口,使得开发得到简化
2: 易于监控,微服务网关可收集监控数据并进行分析
3: 易于认证,可在微服务网关上进行认证,然后在将请求转发给微服务,无须每个微服务都进行认证
4: 减少客户端与微服务之间的交互次数
Request的生命周期

zuul过滤器类型
前置(pre), 路由(route), 后置(post), 错误(error)
zuul的使用
Zuul的基本使用使用非常简单, 只需要2步骤:
1: 引入依赖
<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>
2: 使Zuul可用
@EnableZuulProxy
然后就可以直接使用, 例如调用PRODUCER项目的getProduct的controller则可以直接调用
http://localhost:9000/producer/getProduct
查看所有的routes
http://localhost:9000/actuator/routes
http://localhost:9000/actuator/routes/details
配置解析
1: producer项目通常我们可以通过如下方式访问
http://localhost:9000/producer/getProduct
但是我们如果想修改为自己的命名, 则可以设置zuul.routes.myProducer
zuul:
routes:
myProducer: ##这个名字随便取
path: /myProducer/** ##这个myProducer是目前暴露出去的
serviceId: producer ##这个是想调用的application name
sensitiveHeaders:
prefix: /test
strip-prefix: false
ignored-patterns: ##使下面2个url的访问不可用
- /producer/getProduct
- /myProducer/getProduct
zuul的过滤器
1. 请求参数拦截 (一定要有token)
ZuulFilter.java
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.apache.commons.lang.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_DECORATION_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
@Component
public class TokenFilter extends ZuulFilter {
@Override
public String filterType() {
return PRE_TYPE; //filter类型
}
@Override
public int filterOrder() {
return PRE_DECORATION_FILTER_ORDER - 1;
}
@Override
public boolean shouldFilter() {
return true;
}
//逻辑部分
@Override
public Object run() {
RequestContext requestContext = RequestContext.getCurrentContext();
HttpServletRequest request = requestContext.getRequest();
//从{url:cookie:header}参数获取
String token = request.getParameter("token");
if(StringUtils.isEmpty(token)){
requestContext.setSendZuulResponse(false);
requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
return null;
}
}
2. Response拦截 (在返回中的header中加参数)
AddResponseHeaderFilter.java
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.POST_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SEND_RESPONSE_FILTER_ORDER;
@Component
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 requestContext = RequestContext.getCurrentContext();
HttpServletResponse response = requestContext.getResponse();
response.setHeader("my-header", UUID.randomUUID().toString());
return null;
}
}
3. zuul限流(利用google的令牌桶)
RateLimiterFilter.java
import com.google.common.util.concurrent.RateLimiter;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.exception.ZuulException;
import org.springframework.stereotype.Component;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVLET_DETECTION_FILTER_ORDER;
@Component
public class RateLimiterFilter extends ZuulFilter {
private static final RateLimiter RATE_LIMITER = RateLimiter.create(100);
@Override
public String filterType() {
return PRE_TYPE;
}
@Override
public int filterOrder() {
return SERVLET_DETECTION_FILTER_ORDER -1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
if(!RATE_LIMITER.tryAcquire()){
throw new RateLimiterException();
}
return null;
}
}
4. zuul的跨域
1: 单个方法跨域, 确定是方法太多, 每个都需要注释
@CrossOrigin(allowCredentials="true") //允许cookie跨域
2: 整个跨域
CorsConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import java.util.Arrays;
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter(){
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
final CorsConfiguration config = new CorsConfiguration();
//是否支持cookie跨域
config.setAllowCredentials(true);
//允许的原始域 例如: http://www.a.com
config.setAllowedOrigins(Arrays.asList("*"));
//允许的头
config.setAllowedHeaders(Arrays.asList("*"));
//允许的方法, *表示允许所有的
config.setAllowedMethods(Arrays.asList("*"));
config.setMaxAge(300l);
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}