本次鬥毆事件原由所有歸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...
更多精彩內容請關注微信公衆號:一個程序員的成長