网关zuul
zuul 约 等于 一系列过滤器。
四种过滤器
pre:在请求被路由之前调用,可利用这种过滤器 鉴权。选择微服务,记录日志,限流。
route:在将请求路由到微服务调用,用于构建发送给微服务的请求,并用http clinet(或者ribbon)请求微服务。
post:在调用微服务执行后。可用于添加header,记录日志,将响应发给客户端。
error:在其他阶段发生错误是,走此过滤器。
四种过滤器执行顺序:
灰度发布:
① 用户通过zuul网关进行服务调用;此时进行灰度发布,利用ribbon和eureka的meta进行动态路由
使用eureka的元数据信息,再配上ribbon的路由功能,就可以在api-gateway实现很多功能,比如灰度测试、生产调试等等。下面介绍一下,怎么使用jmnarloch大神提供的ribbon-discovery-filter-spring-cloud-starter,利用简单的几行代码搞定这一切 |
添加pom依赖
<dependency>
<groupId>io.jmnarloch</groupId>
<artifactId>ribbon-discovery-filter-spring-cloud-starter</artifactId>
<version>2.1.0</version>
</dependency>
路由
@Component
public class DynamicRoutesFilter extends ZuulFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(DynamicRoutesFilter.class);
@Override
public String filterType() {
return FilterConstants.ROUTE_TYPE; //使用路由
//return "pre";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException{
RequestContext currentContext = RequestContext.getCurrentContext();
HttpServletRequest request = currentContext.getRequest();
int userId = Integer.parseInt(request.getHeader("userId"));
// 根据用户id 查 规则 查库 v1,meata
// 含义是:查库(动态的)得到发布的规则,如果是v1,matedata的规则也是v1(也可以是在请求头header的属性中配置)
// 匹配上了才走下面的逻辑
// 金丝雀
if (userId == 1){
RibbonFilterContextHolder.getCurrentContext().add("version","v1");
// 普通用户
}else if (userId == 2){
RibbonFilterContextHolder.getCurrentContext().add("version","v2");
}
return null;
}
}
② 新发布服务不经过网关,是内部服务间的调用;利用 @Aspect 切面和自定义 ribbon 的规则 IRule 来实现
api-passenger调用sms服务的时候,通过rule规则,实现特定用户调用某个或某些指定的sms服务
流程:api-passenger的testCall()方法调用sms-test()方法,用postman在request的header中设置属性,userId=1
@Aspect
@Component
public class RequestAspect {
@Pointcut("execution(* com.mashibing.apipassenger.controller..*Controller*.*(..))")
private void anyMehtod(){}
@Before(value = "anyMehtod()")
public void before(JoinPoint joinPoint){
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
String version = request.getHeader("version");
// 灰度规则 匹配的地方 查db,redis ====
if (version.trim().equals("v2")){
RibbonFilterContextHolder.getCurrentContext().add("version","v2");
}
}
}
被拦截的方法
@RestController
@RequestMapping("/test")
public class TestCallServiceSmsController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/call")
public String testCall(){
return restTemplate.getForObject("http://service-sms/test/sms-test",String.class);
}
}
自定义ribbon规则(根据用户信息,选择不同的服务进行分发)。拿到 自定义元数据 metadata
public class MsbRandomRule extends AbstractLoadBalancerRule{
public Server choose(ILoadBalancer lb, Object key) {
// 。。。。省略
System.out.println("MsbRandomRule 自定义rule");
return server;
}
@Override
public Server choose(Object key){
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig){
}
}
/**
* 该类不应该在主应用程序的扫描之下,需要修改启动类的扫描配置。否则将被所有的Ribbon client共享,
* 比如此例中:ribbonRule 对象 会共享。
* 在主类上进行忽略
* @ComponentScan(
* excludeFilters = {
* @ComponentScan.Filter(type = FilterType.ANNOTATION,value = ExcudeRibbonConfig.class)
* })
*/
@ExcudeRibbonConfig //自定义注解,功能同@Configuration
public class RibbonConfiguration {
@Bean
public IRule ribbonRule() {
return new MsbRandomRule();
}
}
token通过网关zuul,不往后传的问题
cookie或者token都是做身份识别或鉴权用的,由各个服务往上提取到网关,由网关来做,那么就不应该再将cookie或者token下发下去了。也可以配置,让cookie可以下发
zuul:
#以下配置,表示忽略下面的值向微服务传播,以下配置为空表示:所有请求头都透传到后面微服务。
sensitive-headers: