• 小伙子把我坑了,改造网关filter,一直报跨域


    闲聊


    1、项目研发负责人需要具备主动性

    阿里招聘简历上,常常会带上一句话:具备owner意识。它的逻辑是怎样的呢?

    【执行者角度】:我完成某项任务,I do it~

    【owner角度】入手任务前,这个任务为了解决什么东西(核心价值)?它会引发你的思考,就是我有没有其他更好的方案去解决这个问题,其次是在实施前思考可行性、风险、扩展点。任务执行中,项目进度是不是在预期内,然后遇到什么问题需要主动寻求帮助。任务完成后,我们做这个项目它有没有发挥应有的价值,这时就要观察项目运转情况、业务情况,如果它是一个持续的过程,那么我们还要规划下一步内容。

    我觉得这是我在当项目负载负责人的时候学习到的,我可以清晰观察到很多项目半死不活,就它只是服务于当下,可能上线后没有多少人去用它,它的价值完全没有发挥出来,just 一个摆设!

    坚持做正确的事 --马斯克

    马斯克在成功之前,大家都觉得他很疯狂,什么回收火箭,面对一次次失败,网上键盘侠噼里啪啦吐槽更猛;当他成功的时候,大家就会觉得很了不起。是啊,很多人只看花绽放的结果,但是花在成长过程,大家就会抗拒新的事物、新的尝试,并且加以诋毁。所以坚持做正确的事~

    前言


    我们最近项目终于开始接入统一登录了,其实sso统一登录项目也耽搁了很长一段时间,然后登录验证逻辑是交给权限中心去搞,也就是需要将之前网关登录鉴权filter改写,通过sdk的方式去注入到网关中。然后到了测试阶段,前端反馈有些接口一直报跨域,我就奇怪了,之前接口一直是好好的,然后网关也有配置跨域设置,咋会这样?

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dH7F9wqN-1668392437436)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/037d094698724eaea777a1614e690be2~tplv-k3u1fbpfcp-watermark.image?)]

    排查历程


    1. 第一步:我观察网关跨域配置是否有问题

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YVcBm5Hv-1668392437437)(https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fc914c2620484c56a77ee938955f8691~tplv-k3u1fbpfcp-watermark.image?)]

    没有问题,就是从网上copy下来的,哈哈哈

    2. 思考:为什么会跨域?

    小伙子提供了请求traceid给我,让我apm看看什么问题,好家伙,这网关给你改造然后你让我来看啥问题?

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dm2cdr4e-1668392437438)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/320fa2f51690498ea4a51675806fb108~tplv-k3u1fbpfcp-watermark.image?)]

    我们看到是能正常返回的,但是!是异常,验证已失效,请重新登录。

    3. 第二步,检查网关跨域配置

    为什么其他服务异常不会跨域,偏偏这登录鉴权异常就跨域?其实浏览器的跨域是因为同源机制导致,就是response需要加上特定header,Access-Control-Allow-Origin,Access-Control-Allow-Credentials;

    那么我就去查网关是否有对异常进行处理:

    @Slf4j
    public class XxxFilter extends AbstractErrorWebExceptionHandler implements Ordered {
    
    
        @Override
        protected RouterFunction getRoutingFunction(ErrorAttributes errorAttributes) {
            return RouterFunctions.route(RequestPredicates.all(), request -> renderErrorJsonResponse(request, errorAttributes));
        }
    
        private Mono renderErrorJsonResponse(ServerRequest request, ErrorAttributes errorAttributes) {
    
            Map errorProperties = getErrorAttributes(request, ErrorAttributeOptions
                    .of(ErrorAttributeOptions.Include.STACK_TRACE));
    
            // 获取合适的处理器对 response body 进行重写
            return rewriteFunctions.stream()
                    .orElseGet(() -> {
                        Throwable throwable = errorAttributes.getError(request);
    
                        return ServerResponse.ok()
                                .contentType(MediaType.APPLICATION_JSON)
                                .body(BodyInserters.fromValue(exceptionAdvice.handleException(throwable)));
                    });
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    网关地方会重写异常的返回response,我idea本地测试一波,发现如果是服务异常,它不会走这里的,也就是只有出现Throwable异常抛出的时候才会被捕获。报错的接口却是走这个异常,问题慢慢揭开面纱~

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RJQ1sYN1-1668392437438)(https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4726d5ccf22040c5bda093fc25d3bb22~tplv-k3u1fbpfcp-watermark.image?)]

    4. 第三步:查看接口的归属以及实现

    我就去瞄了一眼,这个接口是哪个服务的,这是谁的部下,这么勇猛。好家伙,就是这期接入统一登录的接口,而且是白名单!

    接下来我们就要进去看看对应的实现了,逻辑里头没有判断token是否过期啊,怎么肥事,老六。我就找啊找啊,发现居然还自带一个filter来检查访问的token是否有效的

    在这里插入图片描述

    这个就是gaetway web-flux的过滤器写法对吧,到这里还没有问题,我们再往下看

    在这里插入图片描述

    当我看到方法里头的实现的时候,我就觉得坏事了,因为我们网关filter是不会这么写的,直接抛出异常。

    why?

    业务系统我们习惯是throw new xxException对吧,这个没有错,因为业务系统有统一异常捕获。小伙子改造网关filter验证,也认为网关有异常捕获对吧。

    其实呢,网关已经是最外层了,理论上不应该再抛出异常,应该直接返回响应的异常码还有信息。

    到这里,我们就能解释清楚第三步,为啥这个接口走的是网关异常捕获,而不是直接返回了。 因为你在filter这里抛出异常,然后被网关异常handler捕获,重写了response

    注意这里重写了response,导致header头的跨域头丢失了。

    5. 第四步:在网关异常强行加上跨域头

    注意这里是强行加上跨域头,你想想网关怎么可以有抛出异常呢?它只能有异常响应,不能直接抛出异常,它是两回事,前者是封装异常码、异常信息,后者是直接抛出异常,他们区别就是500,系统异常,那是万不得已才去全局捕获的,业务系统还能理解,但是网关的话人家捕获异常是为了防止万一,你偏偏要去通过抛出异常来处理,去走最后兜底方案。

    在这里插入图片描述

    到这里我们就解决了跨域问题

    为什么直接改成输出异常码就不会有问题?


    比如说跨域filter在这个鉴权filter后面,不就跨域头没了对吧,所以我们需要探索他们之间的先后顺序

    首先CorsWebFilter 它是继承webfilter,正儿八经的网关拦截器,然后我们再看下鉴权filter,它也是继承webfilter,这下好玩了,我们只能通过order方法来决定他们的先后顺序。

    其次还有另外做法,实现globalfilter,它虽然带上filter字样,其实是属于webhandler里头一个拦截器责任链。我们通过以前这篇文章介绍到网关构造,会先走webfilter,然后走webhandler,这个顺序不需要设定,一开始会走添加跨域头corsfilter,然后再进去webhandler,这样的好处也有一个,越往前它的粒度是越大的,我们这个鉴权的拦截器是针对网关某些白名单接口去限制的,范围会更小,应该滞后去处理。

    这样的设计网关才符合漏斗形过滤机制,一层一层筛选以及处理!

    在这里插入图片描述

    回顾


    导致的原因其实就是因为接入统一登录的时候,有些权限接口是白名单,通过网关filter来鉴权,但是呢,里头通过抛出异常的方式来实现校验token,导致走了网关兜底异常handler,通过改写response响应,导致跨域头没有塞回去。

    我的观点:
    1、网关filter不应该跟业务系统一样,直接抛出异常,而是直接返回异常码+异常信息+响应头。因为这里只是丢失了跨域头,那么其他什么灰度header标识,或者跟前端约定的东西都会丢失。我认为网关统一异常处理是作为最后兜底的方案去解决,不是作为业务异常来搞的

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lJ8HF9Tb-1668392437440)(https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1e23fc213325468f90ed7f7afc667470~tplv-k3u1fbpfcp-watermark.image?)]

    下课,觉得对你有帮助的,点点赞,关注下博主呗,感谢~

  • 相关阅读:
    How Can We Know What Language Models Know?
    2023Q2全球可穿戴腕带出货量达 4400 万台
    使用cpolar发布群晖NAS上的网页(1)
    OpenGL(十九)——Qt OpenGL波动纹理(旗子的飘动效果)
    Rancher集群之间ssh登录问题
    计组_cpu的结构和工作流程
    Python数据分析:从导入数据到生成报告的全面指南
    全志A523(显示篇一)
    JavaScript篇
    如何系统的学习Python——Python的基本语法
  • 原文地址:https://blog.csdn.net/weixin_38336658/article/details/127842700