专栏首页bingfeng-技术为了一个HTTP请求问题,差点跟iOS干起来

为了一个HTTP请求问题,差点跟iOS干起来

本次斗殴事件起因全部归iOS,为啥这么说,http请求都不会发,瞎写的什么玩意(ps:他应该不会看到...)。

在处理本次冲突中,意外发现了另外一个存在已久的bug,我们先说说这个玩意,再说我们之间的恩怨。因为这是息息相关的。

SpringBoot中的过滤器

过滤器这东西应该很常见了,但是你的过滤器真的起到拦截的作用了吗?这里就算你起到拦截的作用了,但是你的过滤器能拦截到指定的路径吗?先看一下我原始写法。

谨慎参考:

@WebFilter(filterName = "baseFilter", urlPatterns = "/*")
public class BaseFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) {

        System.out.println("baseFilter 拦截了 /*");
        
        filterChain.doFilter(req, resp);
    }
}

首先这里说下,如果你这是特别单纯的加个@WebFilter就以为ok了,那我告诉你,脸会被打的很疼的。

因为这个注解是servlet的,所以你一定要记得在启动类上加@ServletComponentScan此注解,这样在应用启动的时候,过滤器才会被扫描到。

我们写了一个Controller的接口访问了下,可以看到拦截器确实拦截到了我们的请求。

你以为的只是你以为

我们项目有时候大了,不知道引入了什么东西,有时候会导致这个过滤器呢就无法被注入,看到那行报错呢可能脑子还没反应过来,但是CV大法已经打开了度娘,找到了问题原因,度娘说你加个@Commponent注解好了。然后也确实好了,然后接下来他都如何操作。

@Component
@WebFilter(filterName = "baseFilter", urlPatterns = "/user/*")
public class BaseFilter implements Filter {

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) {

        HttpServletRequest request = (HttpServletRequest) req;

        String url = request.getRequestURL().toString();

        System.out.println(url);
        System.out.println("baseFilter 拦截了 /*");
        
        filterChain.doFilter(req, resp);
    }
}

然而,不巧的是加了@Component注解虽然解决了问题,但是呢urlPatterns拦截的指定路径却没有生效。

我这里是一个pub开头的请求,拦截器拦截的user开头的,然后如下:

他居然将所有的请求给我拦截了下来,不是我想象的那样,那我们该如何解决这种问题呢?往下看同学。

SpringBoot如何注入过滤器

这里我就不列举众多的注入方式了,以免混淆大家,我就直接告诉你们怎么正确注入就ok了,本人已经亲测,而且管理起来很是方便。

过滤器写法

过滤器除了实现Filter之外,不要加任何的东西,就是这么简单。

public class BaseFilter implements Filter {


    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain) {

        HttpServletRequest request = (HttpServletRequest) req;

        String url = request.getRequestURL().toString();

        System.out.println(url);
        System.out.println("baseFilter 拦截了 /*");
        
        filterChain.doFilter(req, resp);
    }
}

过滤器注入

我们这里直接通过配置类的方式将过滤器注入,这样呢,我们这里也一目了然,看到我们所有的过滤器,以及过滤器规则。

下面的这些参数都是基本配置,基本都是必填,name你就写过滤器的类名,首字母小写就好了,order就是过滤器的执行顺序,数字越小,越先执行。

这样我们一个完整的过滤器就配置好了。当你再访问/pub接口时,是不会被BaseFilter拦截到的。

「这里也推荐大家以后尽量这样去配置。」

@Configuration
public class FilterConfig {

    @Bean
    public FilterRegistrationBean<BaseFilter> baseFilter() {
        FilterRegistrationBean<BaseFilter> filterBean = new FilterRegistrationBean<>();
        filterBean.setFilter(new BaseFilter());
        filterBean.setName("baseFilter");
        filterBean.addUrlPatterns("/user/*");
        filterBean.setOrder(1);
        return filterBean;
    }
}

我与iOS的一战

我们先看报的错,再来聊聊这次的锅我是怎么甩的

RequestRejectedException: The request was rejected because the URL was not normalized.

看到没因为网址不标准,导致请求被拒绝。

非说我接口有问题,本来想奋起反抗,看到对方比我身材威猛,想想还是抓到实质性证据在甩他吧。

既然说请求网址不正确,我猜测就是请求路径中是不是有什么猫腻,那我们就抓包呗。

最后在我们各种手段之下拿到了真凭实据。诸位法官请看:

他的请求路径:http://127.0.0.1:8080//user/list

他的请求路径中出现了双斜杠,这样肯定报错啊。这里需要说明下,报错是因为引入了Security安全框架。

既然已经确定问题,那我必须奋起反抗,找他甩锅,当他看到这个时候,对吧自己也无话可说,只能默默的把锅背上。

就这样我这次又顺利的甩锅成功。

解决与反思

虽然锅甩出去了,但是问题还是要解决的。

其实按正常逻辑来说,不管我们引入了什么东西,只要请求路径正确,即使路径中出现再多的斜杠,我们也应该做好处理,不能影响用户的访问。所以我们就通过过滤器进行一个处理。

public class UriFormatFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain)
            throws ServletException, IOException {

        // 路径隔离符号
        String separateSymbol = "/";

        String uri = req.getRequestURI();
        StringBuilder newUrl = new StringBuilder();

        String[] split = uri.split(separateSymbol);

        for (String s : split) {
            if (StringUtils.isNotBlank(s)) {
                newUrl.append(separateSymbol).append(s);
            }
        }

        req = new HttpServletRequestWrapper(req) {
            @Override
            public String getRequestURI() {
                return newUrl.toString();
            }
        };
        filterChain.doFilter(req, res);
    }
}

最后将过滤器注入

这里order为啥写-100,如果你写1,你以为它会是第一个执行,其实不然,在执行他之前,可能框架的一些过滤器会先执行,所以为了保险起见,我们就设置为-100,确保请求进来之后先走它。

@Bean
public FilterRegistrationBean<UriFormatFilter> uriFormatFilter() {
    FilterRegistrationBean<UriFormatFilter> filterBean = new FilterRegistrationBean<>();
    filterBean.setFilter(new UriFormatFilter());
    filterBean.setName("uriFormatFilter");
    filterBean.addUrlPatterns("/*");
    filterBean.setOrder(-100);
    return filterBean;
}

注意

如果你在过滤器中注入了一些Mapper、Service之类的话,可能会出现问题,调用的时候被注入的对象可能是个null,这就涉及到类的加载顺序,我就不在这里bibi了,真有人遇到了再说。反正我已经解决了[Doge]。

参考文章:

https://blog.csdn.net/chenmengyijiu/article/details/84561302 https://blog.csdn.net//qq_30062181/article/details///84964691

日拱一卒,功不唐捐

本文分享自微信公众号 - 一个程序员的成长(xiaozaibuluo),作者:一个程序员的成长

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-11-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【云+社区年度征文】Java如何适配请求路径中多余的斜杠

    本次斗殴事件起因全部归iOS,为啥这么说,http请求都不会发,瞎写的什么玩意(ps:他应该不会看到...)。

    一个程序员的成长
  • SpringBoot中的异常处理和参数校验

    兄弟们好,这次来跟老铁交流两个问题,异常和参数校验,在说参数校验之前我们先来说异常处理吧,因为后面参数的校验会牵扯到异常处理这块的内容。

    一个程序员的成长
  • SpringBoot中的异常处理与参数校验

    兄弟们好,这次来跟老铁交流两个问题,异常和参数校验,在说参数校验之前我们先来说异常处理吧,因为后面参数的校验会牵扯到异常处理这块的内容。

    一个程序员的成长
  • 【云+社区年度征文】Java如何适配请求路径中多余的斜杠

    本次斗殴事件起因全部归iOS,为啥这么说,http请求都不会发,瞎写的什么玩意(ps:他应该不会看到...)。

    一个程序员的成长
  • Appium+python自动化(十)- 元素定位秘籍助你打通任督二脉 - 上卷(超详解)

      你有道灵光从天灵盖喷出来你知道吗,年纪轻轻就有一身横练的筋骨,简直百年一见的练武奇才啊,如果有一天让你打通任督二脉,那还不飞龙上天啊。正所谓我不入地狱谁入地...

    北京-宏哥
  • Android实现记事本功能

    本文实例为大家分享了Android实现记事本功能的具体代码,供大家参考,具体内容如下

    砸漏
  • Ubuntu环境源码编译安装xdebug的方法

    本文实例讲述了Ubuntu环境源码编译安装xdebug的方法。分享给大家供大家参考,具体如下:

    砸漏
  • 2-AIII--Service服务的绑定

    张风捷特烈
  • Vue.js学习笔记(4)

    全局组件引入,使用更方便 在main.js中使用 ‘vue.component(‘组件名’, ‘组件对象’);’

    程序员不务正业
  • 360安全扫描之WordPress 页面异常导致本地路径泄漏 的漏洞修补

    今天头脑一热到360安全检测那里去为自己的网站进行安全扫描了一番。上次扫描还是一年前,当初扫描一个网站是 94 分,那时候还不懂代码,就这么挂着,被360 公开...

    Jeff

扫码关注云+社区

领取腾讯云代金券