Spring Cloud网关服务 - Zuul

快速入门

新建zuul-gateway工程,引入pom依赖


    org.springframework.cloud
    spring-cloud-starter-netflix-zuul


    org.springframework.cloud
    spring-cloud-starter-netflix-eureka-client

引导类标注

@EnableZuulProxy
@EnableDiscoveryClient
@SpringBootApplication
public class ZuulGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ZuulGatewayApplication.class, args);
    }

}

基于服务发现配置路由规则

zuul.routes.feign.path=/feign/**
zuul.routes.feign.service-id=feign-consumer

zuul.routes.hello.path=/hello/**
zuul.routes.hello.service-id=hello-service

请求过滤

实现ZuulFilter接口,如果请求内容中没有token,则返回401

@Slf4j
public class AccessFilter extends ZuulFilter {
    @Override
    public String filterType() {  //过滤器类型,这里为pre,标识会在请求被路由之前执行
        return "pre";
    }

    @Override
    public int filterOrder() { //过滤器的执行顺序
        return 0;
    }

    @Override
    public boolean shouldFilter() { //过滤是否会被执行,在应用中可以根据业务需求自定义实现
        return true;
    }

    @Override
    public Object run() throws ZuulException { //过滤器具体逻辑
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();

        log.info("filter..........");

        Object t = request.getParameter("token");
        if(Objects.isNull(t)) {
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
        }
        return null;
    }
}

注入filter实例

@Bean
ZuulFilter filter() {
    return new AccessFilter();
}

路由详解

不依赖于服务治理,单实例配置,通过参数对配置

zuul.routes..path=/feign/**
zuul.routes..service-id=http://localhost:8080

多实例配置

zuul.routes..path=/feign/**
zuul.routes..service-id=MyService
#默认依赖服务发现机制获取服务名对应的实例清单,没有整合eureka,所以需要设置为false
ribbon.eureka.enabled=false 
MyService.ribbon.listOfServers=http://localhost:8080,http://localhost:8081

服务路由的默认规则

在实际应用中,大部分的路由配置几乎都会采用服务名作为请求前缀,对于这种有规则的配置内容,在引入eureka后,zuul会自动创建一个默认路由规则,这个默认规则的path会使用serviceId作为请求前缀

在配置文件中注释掉自定义路由规则

#zuul.routes.feign.path=/feign/**
#zuul.routes.feign.service-id=feign-consumer

直接使用serviceId作为请求前缀发起请求,也可以实现正常访问

http://localhost:8084//ask1?name=sdfsdf&token=sdfsdf

自定义路由规则

可以使用正则表达式自定义路由规则

@Bean
PatternServiceRouteMapper patternServiceRouteMapper() {
    return new PatternServiceRouteMapper("","");
}
  1. 参数一检查服务名称是否匹配正则表达式
  2. 参数二根据服务名定义的内容转换出的路径表达式
路径匹配

采用ant表达式风格,即?//*,这里需要注意的是,路由的保存是有序的,而通过properties文件加载是无序的,可以通过yaml文件来实现有序的路由规则

zuul:
    routes:
        feign:
            path: /feign/**
            service-id: feign-consumer
        hello:
            path: /hello/**
            service-id: hello-service

忽略表达式

通过ignored-patterns可以设置不希望被网关路由的url表达式

zuul.ignored-patterns=/**/hello/*

路由前缀

为网关路由规则增加/api前缀

zuul.prefix=/api

本地跳转

zuul支持forward形式的服务端跳转配置,下面的配置实现了hello跳转到网关/local/hello的功能

zuul.routes.hello.path=/hello/**
zuul.routes.hello.service-id=forward:/local

Cookie和头信息

默认情况下,zuul在请求路由时,会过滤掉http请求头中的一些敏感信息,防止被传递到下游服务器,如Cookie,Authorization,Set-Cookie,但是如果使用了spring security,shrio等安全框架时,需要使用这些敏感信息,可以通过以下两种方式进行配置

全局配置

zuul.sensitive-headers=

指定路由配置

设置敏感头为空

zuul.routes..sensitive-headers=

或开启自定义敏感头

zuul.routes..custom-sensitive-headers=true

在使用安全框架时,登录成功后,会返回302,location指向的是具体的服务地址,而不是网关,可以设置

zuul.add-host-header=true

这样,使得网关在进行路由转发钱设置Host头信息,标识最初的服务器请求地址

Hystrix和ribbon支持

在spring-cloud-starter-netflix-zuul中已经引入了hystrix和ribbon支持,可以设置ribbon及hystrix的相关配置


  org.springframework.cloud
  spring-cloud-starter-netflix-hystrix
  2.2.2.RELEASE
  compile


  org.springframework.cloud
  spring-cloud-starter-netflix-ribbon
  2.2.2.RELEASE
  compile

过滤器详解

zuul中过滤器是实现请求转发最关键的核心部件,每一个进入zuul的http请求都会经过一些列的过滤器处理链得到请求响应并返回给客户端

zuul中实现的过滤器包含四个基本特征,过滤类型,执行顺序,执行条件,具体操作,实际上就是ZuulFilter中定义的四个抽象方法

public class AccessFilter extends ZuulFilter {
    @Override
    public String filterType() {  //过滤器类型,这里为pre,标识会在请求被路由之前执行
        return "pre";
    }

    @Override
    public int filterOrder() { //过滤器的执行顺序
        return 0;
    }

    @Override
    public boolean shouldFilter() { //过滤是否会被执行,在应用中可以根据业务需求自定义实现
        return true;
    }

    @Override
    public Object run() throws ZuulException { //过滤器具体逻辑

    }
}

zuul中,过滤器类型的执行顺序为

pre(customer) -> routing -> post -> error

其中error只有在前序三种过滤器发生错误时才会执行

核心过滤器

zuul中定义了一批核心过滤器位于org.springframework.cloud.netflix.zuul.filters包下

pre阶段

  1. ServletDetectionFilter:用来检查是通过spring的dispatcherServlet处理运行的还是通过ZuulServlet来处理运行的,它的检测结果会保存到当前请求上下文的isDispaterServletRequest参数中
  2. Servlet30WrapperFilter:执行顺序-2,将原始的httpservletequest包装成servelt30requestwrapper对象
  3. FormBodyWrapperFilter:执行顺序-1,仅对两类请求生效,application/x-www-form-urlencoded和multipart/form-data,将该两类请求包装成FormBodyRequestWrapper
  4. DebugFilter:执行顺序1,根据zuul.debug.request和请求中的debug参数决定是否执行过滤器中操作。具体操作则是把debugRouting和debugRequest参数设置为true,在同一个请求的不同生命周期中都可以访问这两个参数,当环境出现问题时,可以通过参数请求方式激活debug分析信息
  5. PreDecorationFilter:执行顺序5,pre阶段最后执行的过滤器,为当前请求设置做预处理

route过滤器

  1. RibbonRoutingFilter:执行顺序10,只对配置serviceId路由规则的请求生效,通过ribbon和hystrix来向服务实例发起请求
  2. SimpleHostRoutingFilter:执行顺序100,只对配置url路由规则的请求生效
  3. SendForwardFilter:执行顺序500,处理路由配置中forward本地跳转

post过滤器

  1. SendErrorFilter:执行顺序0,将请求上下文中的错误信息来组成一个forward到api网关/error错误端点产生错误响应
  2. SendResponseFilter:执行顺序1000,利用请求上下文组织需要发送会客户端的响应内容
异常处理

使用errorfilter自定义异常处理,流转到SendErrorFilter

@Slf4j
public class ErrorFilter extends ZuulFilter {
    @Override
    public String filterType() {  //过滤器类型,这里为pre,标识会在请求被路由之前执行
        return "error";
    }

    @Override
    public int filterOrder() { //过滤器的执行顺序
        return 10;
    }

    @Override
    public boolean shouldFilter() { //过滤是否会被执行,在应用中可以根据业务需求自定义实现
        return true;
    }

    @Override
    public Object run() throws ZuulException { //过滤器具体逻辑
        RequestContext ctx = RequestContext.getCurrentContext();
        Throwable t = ctx.getThrowable();

        log.info("filter..........");
        
        ctx.set("error.status_code",HttpStatus.BAD_GATEWAY.value());
        ctx.set("error.exception",t.getCause());
        return null;
    }
}

你可能感兴趣的:(Spring Cloud网关服务 - Zuul)