RESTful API的攔截

  • 過濾器(Filter)

依賴于servlet容器。在實現(xiàn)上基于函數(shù)回調(diào),可以對幾乎所有請求進行過濾,但是缺點是一個過濾器實例只能在容器初始化時調(diào)用一次。使用過濾器的目的是用來做一些過濾操作,獲取我們想要獲取的數(shù)據(jù),比如:在過濾器中修改字符編碼;在過濾器中修改HttpServletRequest的一些參數(shù),包括:過濾低俗文字、危險字符等


@Slf4j
//@Component
public class TimeFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("time filter init");
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("filter start");
        long startTime = new Date().getTime();
        filterChain.doFilter(servletRequest, servletResponse);
        log.info("consumingTime:{}",new Date().getTime()-startTime);
        log.info("filter end");
    }
    @Override
    public void destroy() {
        log.info("time filter destroy");
    }
}
@Configuration
public class WebConfig implements WebMvcConfigurer{
    @Bean
    public FilterRegistrationBean timeFilter() {
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new TimeFilter());
        ArrayList<String> urls = new ArrayList<>();
        urls.add("/*");
        registrationBean.setUrlPatterns(urls);
        return registrationBean;
    }
}
  • 過濾器生命周期
    • Filter的創(chuàng)建和銷毀由web服務(wù)器負(fù)責(zé)。 web應(yīng)用程序啟動時,web服務(wù)器將創(chuàng)建Filter的實例對象,并調(diào)用其init方法,完成對象的初始化功能,從而為后續(xù)的用戶請求作好攔截的準(zhǔn)備工作,filter對象只會創(chuàng)建一次,init方法也只會執(zhí)行一次。通過init方法的參數(shù),可獲得代表當(dāng)前filter配置信息的FilterConfig對象。
    • web容器調(diào)用destroy方法銷毀Filter。destroy方法在Filter的生命周期中僅執(zhí)行一次。在destroy方法中,可以釋放過濾器使用的資源。

  • 攔截器(Interceptor)

攔截器是AOP實現(xiàn)的一種策略,在AOP中用于在訪問某個方法或字段之前,進行攔截,在執(zhí)行之前或之后加入某些處理。
SpringMVC 中的Interceptor 攔截請求是通過HandlerInterceptor 來實現(xiàn)的。在SpringMVC 中定義一個Interceptor 非常簡單,主要有兩種方式,第一種方式是要定義的Interceptor類要實現(xiàn)了Spring 的HandlerInterceptor 接口,或者是這個類繼承實現(xiàn)了HandlerInterceptor 接口的類,比如Spring 已經(jīng)提供的實現(xiàn)了HandlerInterceptor 接口的抽象類HandlerInterceptorAdapter ;第二種方式是實現(xiàn)Spring的WebRequestInterceptor接口,或者是繼承實現(xiàn)了WebRequestInterceptor的類。


@Slf4j
@Component
public class TimeInterceptor implements HandlerInterceptor {
  //在handler執(zhí)行之前,返回 boolean 值,true 表示繼續(xù)執(zhí)行,false 為停止執(zhí)行并返回
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("preHandle");
        //攔截器可以拿到請求轉(zhuǎn)向的具體類和方法
        log.info(((HandlerMethod) handler).getBean().getClass().getName());
        log.info(((HandlerMethod) handler).getMethod().getName());
        request.setAttribute("startTime", new Date().getTime());
        return true;
    }
    //在handler執(zhí)行之后, 可以在返回之前對返回的結(jié)果進行修改 
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("postHandle consumingTime:{}", new Date().getTime() - (long) request.getAttribute("startTime"));
    }
  //進行資源清理工作
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("afterCompletion consumingTime:{},ex:{}", new Date().getTime() - (long) request.getAttribute("startTime"), ex);

    }
}
@Configuration
public class WebConfig implements WebMvcConfigurer{
    @Autowired
    private TimeInterceptor timeInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(timeInterceptor);
    }
}
  • 兩者比較
    1. filter基于函數(shù)回調(diào),interceptor基于java反射機制;
    2. filter依賴于servlet容器; 攔截器是一個Spring的組件,歸Spring管理,配置 在Spring文件中,因此能使用Spring里的任何資源、對象,例如 Service對象、數(shù)據(jù)源、事務(wù)管理等,通過IoC注入到攔截器即可。
    3. filter對所有的請求進行過濾,interceptor只對action請求起作用。
    4. 在action的生命周期里,Interceptor可以被多次調(diào)用,而Filter只能在容器初始化時調(diào)用一次。
    5. 執(zhí)行順序:過濾前-攔截前-action執(zhí)行-攔截后-過濾后

  • 切片(Aspect)


    image.png
@Aspect
@Component
@Slf4j
public class TimeAspect {
    @Around("execution(* com.dzg.web.controller.UserController.*(..))")
    public Object handleControllerMethod(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("timeAspect start");
        Object proceed = joinPoint.proceed();
        //Aspect可以拿到請求中的攜帶的參數(shù)信息,這是攔截器無法做到的,但其無法拿到request和response
        Object[] args = joinPoint.getArgs();
        for(Object arg :args){
            log.info("arg:{}",arg);
        }
        log.info("timeAspect end");
        return proceed;

    }
}
  • 攔截順序
    image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • RESTful API的攔截 場景:對RESTfulAPI作統(tǒng)一的處理,比如希望對所有的RESTfulAPI記錄服...
    我可能是個假開發(fā)閱讀 1,999評論 0 14
  • 【原創(chuàng)文章,轉(zhuǎn)載請注明原文章地址,謝謝!】 上一節(jié)我們介紹了Jesery中的過濾器。過濾器主要用來處理請求頭,響應(yīng)...
    叩丁狼教育閱讀 7,365評論 1 2
  • 飛鳥在天空劃出鉛色的痕跡, 遠(yuǎn)走,高飛, 徒留我形單孤寂。 陰云在天空織出灰色的布匹, 迷蒙,暗沉, 只令我停步站...
    小卜姑娘閱讀 1,914評論 51 49
  • ? 五、血濺巡按府 村民拉大徳他們正要出去行刑時,忽聽大德長呼一聲,淚如雨下,說道:“想我秦家一世忠良,卻被奸人所...
    wangfengqun閱讀 330評論 0 0
  • 產(chǎn)品經(jīng)理得title是什么,很重要么?很多產(chǎn)品新人,都被誤導(dǎo)了,總以為作為PM是可以改變世界,創(chuàng)造世界,其實非也。...

友情鏈接更多精彩內(nèi)容