springcloud - 服务网关zuul

Eureka用于服务的注册于发现,Feign支持服务的调用以及均衡负载,Hystrix处理服务的熔断防止故障扩散,Spring Cloud Config服务集群配置中心,似乎一个微服务框架已经完成了。

我们还是少考虑了一个问题,外部的应用如何来访问内部各种各样的微服务呢?在微服务架构中,后端服务往往不直接开放给调用端,而是通过一个API网关根据请求的url,路由到相应的服务。当添加API网关后,在第三方调用端和服务提供方之间就创建了一面墙,这面墙直接与调用方通信进行权限控制,后将请求均衡分发给后台服务端。

基本使用:

新建项目 api-gateway

 application.properties配置

#应用名
spring.application.name=api-gateway

#这里是用了订单系统的配置中心 所以这样配置
spring.cloud.config.discovery.enabled=true
spring.cloud.config.discovery.service-id=CONFIG
spring.cloud.config.profile=dev

#注册到注册中心
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

#配置端口号
server.port=9000

启动类加上@EnableZuulProxy注解

启动priduct服务和api-gateway网关服务,通过网关服务访问地址http://localhost:9000/product/product/list,第一个product是eureka应用服务名,后面的是请求方法的路径。和直接访问product服务地址结果是一样的http://localhost:8080/product/list

自定义路由:

如上地址变成http://localhost:9000/myProduct/product/list

添加配置:-> 访问地址测试。

#自定义路由规则
#zuul.routes.myProduct.path=/myProduct/**
#需要自定义路由的应用
#zuul.routes.myProduct.serviceId=product
#简洁写法
zuul.routes.product=/myProduct/**

禁止路由访问:

添加配置:-> 访问地址测试。

#禁止路由访问
zuul.ignored-patterns=/**/product/**

Cookie

zuul默认是过滤cookie的,访问路由地址http://localhost:9000/product/product/list看看cookies有没传过去。

解决方法:

zuul.sensitive-headers=*

动态路由

增加zuul配置类

@Component
public class ZuulConfig {
    
    @ConfigurationProperties("zuul")
    @RefreshScope
    @Bean
    public ZuulProperties zuulProperties(){
        return new ZuulProperties();
    }
}

最后把上面所有的配置放到git上面去,实现动态路由。

路由和高可用

启动多个服务节点注册到注册中心就可以了,内部调用的时候a服务调用到某个zuul服务转发到b服务,外部调用的话可以用混搭的方式nginx+zuul,nginx对外暴露一个地址,nginx作负载均衡,把请求转发到zuul服务上,两个结合取长补短。

Zuul的核心

Filter是Zuul的核心,用来实现对外服务的控制。Filter的生命周期有4个,分别是“PRE”、“ROUTING”、“POST”、“ERROR”,整个生命周期可以用下图来表示。

Zuul大部分功能都是通过过滤器来实现的,这些过滤器类型对应于请求的典型生命周期。

  • PRE: 这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
  • ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用Apache HttpClient或Netfilx Ribbon请求微服务。
  • POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
  • ERROR:在其他阶段发生错误时执行该过滤器。 除了默认的过滤器类型,Zuul还允许我们创建自定义的过滤器类型。例如,我们可以定制一种STATIC类型的过滤器,直接在Zuul中生成响应,而不将请求转发到后端的微服务。

Zuul:Pre和Post过滤器

PRE:如何对请求作统一的校验:(所有经过zuul请求的都带上token参数,并且不能为空,不然权限校验不通过)

修改api-gateway服务

创建一个filter过滤器

@Component
public class TokenFilter extends ZuulFilter {
    //FilterConstants常量类
    @Override
    public String filterType() { return PRE_TYPE; }

    //过滤器顺序 看FilterConstants常量类里面有
    // 这里放到PRE_DECORATION_FILTER_ORDER之前,越小越靠前
    @Override
    public int filterOrder() { return PRE_DECORATION_FILTER_ORDER - 1; }

    @Override
    public boolean shouldFilter() { return true; }

    @Override
    public Object run() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletRequest request = requestContext.getRequest();
        String token = request.getParameter("token");
        if (StringUtils.isEmpty(token)){
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        return null;
    }
}

添加Bean

    @Bean
    public TokenFilter zuulPreFilter() {
        return new TokenFilter();
    }

测试访问地址http://localhost:9000/myProduct/product/list?token=123444http://localhost:9000/myProduct/product/list

POST过滤器:返回结果头写信息

创建一个filter过滤器

@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() throws ZuulException {
        RequestContext requestContext = RequestContext.getCurrentContext();
        HttpServletResponse response = requestContext.getResponse();
        response.setHeader("X-Foo", UUID.randomUUID().toString());
        return null;
    }
}
    @Bean
    public AddResponseHeaderFilter addResponseHeaderFilter() {
        return new AddResponseHeaderFilter();
    }

 

Zuul限流:

时机:请求转发之前调用

令牌桶算法:以固定速率放入,web请求先要获取令牌,成功才转发。

创建过滤器:

@Component
public class RateLimitFilter extends ZuulFilter{

    //google令牌桶算法实现的组件
    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 {
        RequestContext requestContext = RequestContext.getCurrentContext();
        if (!RATE_LIMITER.tryAcquire()){
            requestContext.setSendZuulResponse(false);
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        return null;
    }
}
    @Bean
    public RateLimitFilter rateLimiter() {
        return new RateLimitFilter();
    }

猜你喜欢

转载自blog.csdn.net/qq_26857649/article/details/82905384