攔截器
要了解Spring攔截器的作用尘惧,我們需要先解釋一下HTTP請求的執(zhí)行鏈惭适。DispatcherServlet捕獲每個請求笙瑟。調(diào)度員做的第一件事就是將接收到的URL和相應(yīng)的controller進行映射(controller必須恰到好處地處理當(dāng)前的請求)。但是癞志,在到達對應(yīng)的controller之前往枷,請求可以被攔截器處理。這些攔截器就像過濾器凄杯。只有當(dāng)URL找到對應(yīng)于它們的映射時才調(diào)用它們错洁。在通過攔截器(攔截器預(yù)處理,其實也可以說前置處理)進行前置處理后戒突,請求最終到達controller屯碴。之后,發(fā)送請求生成視圖膊存。但是在這之前导而,攔截器還是有可能來再次處理它(攔截器后置處理)忱叭。只有在最后一次操作之后,視圖解析器才能捕獲數(shù)據(jù)并輸出視圖今艺。
在Spring Boot中韵丑,攔截器分為兩類:
一種是對請求進來的url進行攔截,HandlerInterceptor接口虚缎;
一種是對發(fā)送出去的請求進行攔截撵彻,ClientHttpRequestInterceptor。
處理程序映射攔截器基于org.springframework.web.servlet.HandlerInterceptor接口遥巴。和之前簡要描述的那樣千康,它們可以在將其發(fā)送到控制器(方法前使用preHandle)之前或之后(方法后使用postHandle)攔截請求享幽。preHandle方法返回一個布爾值铲掐,如果返回false,則可以在執(zhí)行鏈中執(zhí)行中斷請求處理值桩。此接口中還有一個方法afterCompletion摆霉,只有在preHandler方法發(fā)送為true時才會在渲染視圖后調(diào)用它(完成請求處理后的回調(diào),即渲染視圖后)奔坟。
攔截器也可以在新線程中啟動携栋。在這種情況下,攔截器必須實現(xiàn)org.springframework.web.servlet.AsyncHandlerInterceptor接口咳秉。它繼承HandlerInterceptor并提供一個方法afterConcurrentHandlingStarted婉支。每次處理程序得到正確執(zhí)行時,都會調(diào)用此方法而不是調(diào)用postHandler()和afterCompletion()澜建。它也可以對發(fā)送請求進行異步處理向挖。通過Spring源碼此方法注釋可以知道,這個方法的典型的應(yīng)用是可以用來清理本地線程變量炕舵。
public class LotteryInterceptor implements HandlerInterceptor {
public static final String ATTR_NAME = "lottery_winner";
private static final Logger LOGGER = LoggerFactory.getLogger(LotteryInterceptor.class);
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception exception) throws Exception {
LOGGER.debug("[LotteryInterceptor] afterCompletion");
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView view) throws Exception {
LOGGER.debug("[LotteryInterceptor] postHandle");
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
LOGGER.debug("[LotteryInterceptor] preHandle");
if (request.getSession().getAttribute(ATTR_NAME) == null) {
Random random = new Random();
int i = random.nextInt(10);
request.getSession().setAttribute(ATTR_NAME, i%2 == 0);
}
return true;
}
}
關(guān)于相應(yīng)controller中要展示的信息:
@Controller
public class TestController {
private static final Logger LOGGER = LoggerFactory.getLogger(TestController.class);
@RequestMapping(value = "/test", method = RequestMethod.GET)
public String test(HttpServletRequest request) {
LOGGER.debug("Controller asks, are you a lottery winner ? "+request.getSession().getAttribute(LotteryInterceptor.ATTR_NAME));
return "test";
}
}
結(jié)果:
[LotteryInterceptor] preHandle
Controller asks, are you a lottery winner ? false
[LotteryInterceptor] postHandle
[LotteryInterceptor] afterCompletion
HandlerInterceptor和ClientHttpRequestInterceptor的區(qū)別
HandlerInterceptor 和 ClientHttpRequestInterceptor 都是 Spring 框架中的攔截器何之,但它們的作用和使用場景不同。下面是它們之間的主要區(qū)別:
作用范圍:
HandlerInterceptor 主要用于攔截處理 Spring 應(yīng)用中接收到的 HTTP 請求咽筋。它允許你在請求處理之前溶推、處理之后、以及視圖渲染完成后執(zhí)行自定義邏輯奸攻。
ClientHttpRequestInterceptor 主要用于攔截和處理 Spring 應(yīng)用中使用 RestTemplate 或 WebClient 發(fā)送的 HTTP 請求蒜危。它讓你在請求發(fā)送之前,對請求頭睹耐、請求體等進行自定義處理辐赞。
使用場景:
HandlerInterceptor 通常用于身份驗證、授權(quán)疏橄、日志記錄占拍、跨域資源共享(CORS)等應(yīng)用內(nèi)請求處理相關(guān)的功能略就。
ClientHttpRequestInterceptor 通常用于處理服務(wù)間通信,例如在請求頭中添加認證信息晃酒、自定義請求頭表牢、請求數(shù)據(jù)處理、重試策略等贝次。
過濾器
在 Spring Boot 中崔兴,過濾器(Filter)是用于在 Servlet 容器級別攔截和處理 HTTP 請求的組件。它們通常用于實現(xiàn)諸如身份驗證蛔翅、授權(quán)敲茄、日志記錄、請求和響應(yīng)的數(shù)據(jù)轉(zhuǎn)換等功能山析。過濾器位于整個請求處理鏈的最前端堰燎,因此在請求到達 Spring 應(yīng)用的任何其他組件之前,都會先經(jīng)過過濾器處理笋轨。
過濾器和攔截器各自優(yōu)勢與區(qū)別秆剪?
過濾器(Filter)和攔截器(Interceptor)在某些方面的功能確實相似,但它們在使用場景爵政、處理層級和實現(xiàn)方式上有所不同仅讽。以下是過濾器和攔截器之間的主要區(qū)別和各自的優(yōu)勢:
處理層級:
過濾器(Filter)基于 Java Servlet 規(guī)范,在 Servlet 容器級別處理請求钾挟。過濾器在整個請求處理鏈的最前端洁灵,因此在請求到達 Spring 應(yīng)用的任何其他組件之前,都會先經(jīng)過過濾器處理掺出。
攔截器(Interceptor)是 Spring MVC 的一部分徽千,用于處理 Spring 應(yīng)用中接收到的請求。攔截器在 Spring 處理請求的過程中起作用蛛砰,位于過濾器之后罐栈。
使用場景:
過濾器(Filter)通常用于實現(xiàn)通用的、與框架無關(guān)的功能泥畅,如身份驗證荠诬、授權(quán)、日志記錄位仁、請求和響應(yīng)的數(shù)據(jù)轉(zhuǎn)換等柑贞。
攔截器(Interceptor)通常用于實現(xiàn)與 Spring 框架相關(guān)的功能,如驗證用戶身份聂抢、授權(quán)钧嘶、請求參數(shù)處理、異常處理等琳疏。
優(yōu)勢:
過濾器(Filter)可以處理任何 Web 應(yīng)用的請求有决,不局限于 Spring闸拿。過濾器允許你在請求到達任何框架組件之前對其進行處理,提供了更大的控制范圍书幕。
攔截器(Interceptor)更緊密地集成在 Spring MVC 中新荤,因此可以更方便地使用 Spring 提供的功能。攔截器可以訪問 Spring 上下文台汇,讓你能夠輕松地使用其他 Spring 組件和服務(wù)苛骨。
實現(xiàn)方式:
過濾器(Filter)需要實現(xiàn) javax.servlet.Filter 接口,并實現(xiàn) init苟呐、doFilter 和 destroy 方法痒芝。
攔截器(Interceptor)需要實現(xiàn) HandlerInterceptor 接口(對于請求攔截)或 ClientHttpRequestInterceptor 接口(對于客戶端請求攔截),并實現(xiàn)相應(yīng)的方法牵素。
總的來說严衬,過濾器和攔截器在功能上有一定的重疊,但它們的使用場景两波、處理層級和實現(xiàn)方式有所不同瞳步。選擇使用過濾器還是攔截器取決于你的具體需求和場景闷哆。當(dāng)你需要處理與框架無關(guān)的請求時腰奋,可以使用過濾器;當(dāng)你需要實現(xiàn)與 Spring 框架相關(guān)的功能時抱怔,攔截器可能是更好的選擇劣坊。