本次鬥毆事件起因全部歸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/chenmen...
https://blog.csdn.net//qq_300...
更多精彩內容請關注微信公眾號:一個程式設計師的成長