服务网关过滤器

过滤器作用

我们的微服务应用提供的接口就可以通过统一的API网关入口被客户端访问到了。但是,每个客户端用户请求微服务应用提供的接口时,它们的访问权限往往都需要有一定的限制,系统并不会将所有的微服务接口都对它们开放。然而,目前的服务路由并没有限制权限这样的功能,所有请求都会被毫无保留地转发到具体的应用并返回结果,为了实现对客户端请求的安全校验和权限控制,最简单和粗暴的方法就是为每个微服务应用都实现一套用于校验签名和鉴别权限的过滤器或拦截器。

不过,这样的做法并不可取,它会增加日后的系统维护难度,因为同一个系统中的各种校验逻辑很多情况下都是大致相同或类似的,这样的实现方式会使得相似的校验逻辑代码被分散到了各个微服务中去,冗余代码的出现是我们不希望看到的。所以,比较好的做法是将这些校验逻辑剥离出去,构建出一个独立的鉴权服务。在完成了剥离之后,有不少开发者会直接在微服务应用中通过调用鉴权服务来实现校验,但是这样的做法仅仅只是解决了鉴权逻辑的分离,并没有在本质上将这部分不属于业余的逻辑拆分出原有的微服务应用,冗余的拦截器或过滤器依然会存在。

对于这样的问题,更好的做法是通过前置的网关服务来完成这些非业务性质的校验。由于网关服务的加入,外部客户端访问我们的系统已经有了统一入口,既然这些校验与具体业务无关,那何不在请求到达的时候就完成校验和过滤,而不是转发后再过滤而导致更长的请求延迟。同时,通过在网关中完成校验和过滤,微服务应用端就可以去除各种复杂的过滤器和拦截器了,这使得微服务应用的接口开发和测试复杂度也得到了相应的降低。

为了在API网关中实现对客户端请求的校验,我们将需要使用到Spring Cloud Zuul的另外一个核心功能:过滤器。

Zuul允许开发者在API网关上通过定义过滤器来实现对请求的拦截与过滤,实现的方法非常简单,我们只需要继承ZuulFilter抽象类并实现它定义的四个抽象函数就可以完成对请求的拦截和过滤了。

过滤器的实现

比如下面的代码,我们定义了一个简单的Zuul过滤器,它实现了在请求被路由之前检查HttpServletRequest中是否有accessToken参数,若有就进行路由,若没有就拒绝访问,返回401 Unauthorized错误。

public  class  AccessFilter  extends  ZuulFilter {
private  static  Logger log = LoggerFactory.getLogger(AccessFilter. class );
@Override
public  String filterType() {
return  "pre" ;
}
@Override
public  int  filterOrder() {
return  0 ;
}
@Override
public  boolean  shouldFilter() {
return  true ;
}
@Override
public  Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info( "send {} request to {}" , request.getMethod(), request.getRequestURL().toString());
Object accessToken = request.getParameter( "accessToken" );
if (accessToken ==  null ) {
log.warn( "access token is empty" );
ctx.setSendZuulResponse( false );
ctx.setResponseStatusCode( 401 );
return  null ;
}
log.info( "access token ok" );
return  null ;
}
}

在上面实现的过滤器代码中,我们通过继承ZuulFilter抽象类并重写了下面的四个方法来实现自定义的过滤器。这四个方法分别定义了:

  • filterType:过滤器的类型,它决定过滤器在请求的哪个生命周期中执行。这里定义为pre,代表会在请求被路由之前执行。

  • filterOrder:过滤器的执行顺序。当请求在一个阶段中存在多个过滤器时,需要根据该方法返回的值来依次执行。

  • shouldFilter:判断该过滤器是否需要被执行。这里我们直接返回了true,因此该过滤器对所有请求都会生效。实际运用中我们可以利用该函数来指定过滤器的有效范围。

  • run:过滤器的具体逻辑。这里我们通过ctx.setSendZuulResponse(false)令zuul过滤该请求,不对其进行路由,然后通过ctx.setResponseStatusCode(401)设置了其返回的错误码,当然我们也可以进一步优化我们的返回,比如,通过ctx.setResponseBody(body)对返回body内容进行编辑等。

在实现了自定义过滤器之后,它并不会直接生效,我们还需要为其创建具体的Bean才能启动该过滤器,比如,在应用主类中增加如下内容:

@EnableZuulProxy
@SpringCloudApplication
public  class  Application {
public  static  void  main(String[] args) {
new  SpringApplicationBuilder(Application. class ).web( true ).run(args);
}
@Bean
public  AccessFilter accessFilter() {
return  new  AccessFilter();
}
}

到这里,对于Spring Cloud Zuul过滤器的基本功能就以介绍完毕。读者可以根据自己的需要在服务网关上定义一些与业务无关的通用逻辑实现对请求的过滤和拦截,比如:签名校验、权限校验、请求限流等功能。


从现在开始,我这边会将近期研发的springcloud微服务云架构的搭建过程和精髓记录下来,帮助更多有兴趣研发spring cloud框架的朋友,希望可以帮助更多的好学者。大家来一起探讨spring cloud架构的搭建过程及如何运用于企业项目。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Spring Cloud Gateway 中,可以使用 SkyWalking 提供的插件来实现链路追踪。具体步骤如下: 1. 添加 SkyWalking 插件的依赖: ```xml <dependency> <groupId>org.apache.skywalking</groupId> <artifactId>apm-toolkit-trace</artifactId> <version>${skywalking.version}</version> </dependency> <dependency> <groupId>org.apache.skywalking</groupId> <artifactId>apm-toolkit-opentracing</artifactId> <version>${skywalking.version}</version> </dependency> <dependency> <groupId>org.apache.skywalking</groupId> <artifactId>apm-toolkit-log4j-1.x</artifactId> <version>${skywalking.version}</version> </dependency> ``` 其中 `${skywalking.version}` 是 SkyWalking 版本号。 2. 创建一个 `GlobalFilter`,在该过滤器中添加 SkyWalking 的 `TracingContext`: ```java @Component public class SkyWalkingFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { Tracer tracer = TracingContext.Tracing().tracer(); Span span = tracer.createEntrySpan(exchange.getRequest().getURI().getPath()); try { // 在这里处理逻辑 return chain.filter(exchange); } finally { span.asyncFinish(); } } @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE; } } ``` 在过滤器中使用 `TracingContext.Tracing().tracer()` 获取当前线程的 `Tracer`,并使用 `tracer.createEntrySpan()` 创建一个入口 Span。在请求处理完成后,需要在 `finally` 块中调用 `span.asyncFinish()` 来结束该 Span。 3. 在 `application.yml` 中配置 SkyWalking: ```yaml skywalking: trace: ignore-path: /actuator/** ignored-tracers: org.springframework.cloud.gateway.filter.factory.rewrite.CachedBodyOutputMessage ``` 其中 `ignore-path` 表示不进行链路追踪的路径,`ignored-tracers` 表示需要忽略的 Tracer。 4. 启动 SkyWalking Agent,就可以在 SkyWalking 的控制台中看到链路追踪信息了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值