Solon v3.0.3

八、网关全局过滤器(CloudGatewayFilter)

</> markdown

CloudGatewayFilter 是 ExFilter 的扩展接口,主要是为了突出名字的专属性。使用时与 Filter 的区别:

  • 最后要返回一个 Mono<Void>用于触发一个响应式订阅,从而让异步结束
  • 所有的异常,也要用 Mono.error(err) 返回

作用范围是网关全局。

1、网关全局过滤器

接口说明
CloudGatewayFilter原始网关接口
CloudGatewayFilterMix组合网关接口,可以方便组合 RoutePredicateFactory
  • CloudGatewayFilter 示例(原始接口)
@Component
public class CloudGatewayFilterImpl implements CloudGatewayFilter {
    @Override
    public Completable doFilter(ExContext ctx, ExFilterChain chain) {
        //代码写这儿
        return chain.doFilter(ctx);
    }
}
  • CloudGatewayFilterMix 示例(虚拟类,组合网关接口)
@Component
public class CloudGatewayFilterMixImpl extends CloudGatewayFilterMix {
    @Override
    public void register() {
        //配置写这儿 
        filter("StripPrefix=1");
        filter("AddRequestHeader=app.ver,1.0");
    }

    @Override
    public Completable doFilterDo(ExContext ctx, ExFilterChain chain) {
        //组合过滤器执行后的,代码写这儿
        return chain.doFilter(ctx);
    }
}

2、示例:鉴权

此示例,检查有没有 "TOKEN" 的头信息,如果没有就 401 输出并中止。

@Component(index = -9) //index 为可选
public class AuthGatewayFilterImpl implements CloudGatewayFilter { 
    @Override
    public Completable doFilter(ExContext ctx, ExFilterChain chain) {
        String token = ctx.rawHeader("TOKEN");

        if (token == null) {
            //如果没有 TOKEN 表示失败
            String resultStr = ONode.stringify(Result.failure(401, "签权失败"));

            //ctx.newResponse().status(401);
            ctx.newResponse().header("Content-Type", "application/json;charset=UTF-8");
            ctx.newResponse().body(Buffer.buffer(resultStr));
            return Completable.complete();
        }

        return chain.doFilter(ctx);
    }
}

2、示例:全局异常处理

全局异常处理的过滤器,尽量放到最外层。这个风格跟同步的区别有点大。

@Component(index = -99)
public class CloudGatewayFilterImpl implements CloudGatewayFilter {
    @Override
    public Completable doFilter(ExContext ctx, ExFilterChain chain) {
        return Completable.create(emitter -> {
            chain.doFilter(ctx).subscribe(new CompletableSubscriber() {
                @Override
                public void onError(Throwable e) {
                    if (e instanceof StatusException) {
                        StatusException se = (StatusException) e;

                        ctx.newResponse().status(se.getCode());
                        emitter.onComplete();
                    } else {
                        ctx.newResponse().status(500);
                        emitter.onComplete();
                    }
                }

                @Override
                public void onComplete() {
                    emitter.onComplete();
                }
            });
        });
    }
}