本次斗殴事件原由所有归iOS,为啥这么说,http请求都不会发,瞎写的什么玩意(ps:他应该不会看到...)。程序员
在处理本次冲突中,意外发现了另一个存在已久的bug,咱们先说说这个玩意,再说咱们之间的恩怨。由于这是息息相关的。安全
过滤器这东西应该很常见了,可是你的过滤器真的起到拦截的做用了,这里就算你起到拦截的做用了,可是你的过滤器能拦截到指定的路径吗?先看一下我原始写法。微信
谨慎参考:app
@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此注解,这样在应用启动的时候,过滤器才会被扫描到。ide
咱们写了一个Controller的接口访问了下,能够看到拦截器确实拦截到了咱们的请求。ui
咱们项目有时候大了,不知道引入了什么东西,有时候会致使这个过滤器呢就没法被注入,看到那行报错呢可能脑子还没反应过来,可是CV大法已经打开了度娘,找到了问题缘由,度娘说你加个@Commponent注解好了。而后也确实好了,而后接下来他都如何操做。url
@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拦截的指定路径却没有生效。spa
我这里是一个pub开头的请求,拦截器拦截的user开头的,而后以下:.net
他竟然将全部的请求给我拦截了下来,不是我想象的那样,那咱们该如何解决这种问题呢?往下看同窗。
这里我就不列举众多的注入方式了,以避免混淆你们,我就直接告诉大家怎么正确注入就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; } }
咱们先看报的错,再来聊聊此次的锅我是怎么甩的
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/chenmen...
https://blog.csdn.net//qq_300...
更多精彩内容请关注微信公众号:一个程序员的成长