Yuko Kasahara
Yuko Kasahara

Reputation: 113

How do I enable a filter for url that includes a certain word?

I'm trying to log requests to certain URLs using a filter.

These certain URLs I want are the ones that include the word api so anything from "/aaaa/api" to "/api/items/3".

I had URL patterns set in Filter Config from before I was told to change it to match any URL with "api" in it but I deleted that and used regex to filter URLs in my ApiLogFilter instead as shown below.

My question is: Is there a way to achieve this by editing the pattern of addUrlPatterns in Filter Config? Also, what is the best practice?

@Configuration
public class FilterConfig {

@Bean
public FilterRegistrationBean<ApiLogFilter> 
filterRegistrationBean() {
    FilterRegistrationBean<ApiLogFilter> registrationBean = new 
FilterRegistrationBean();
    registrationBean.setFilter(new ApiLogFilter());
    registrationBean.addUrlPatterns("/api/items/*");
    return registrationBean;
}
@Override
public final void doFilterInternal(
        HttpServletRequest request, HttpServletResponse response, 
FilterChain filterChain)
        throws ServletException, IOException {
    // 処理の開始時間を記録
    long startTime = System.currentTimeMillis();
    // フィルターチェーンの次のフィルターにリクエストとレスポンスを渡す
    filterChain.doFilter(request, response);
    // 処理が戻ってきた時間から処理時間を記録
    long processingTime = System.currentTimeMillis() - startTime;

    // logs only if the request URL follows this pattern
    if (request.getRequestURI().matches(".*/api/.*")) {
        // ログ出力
        logger.info(
                "{} \"{} {}\" {} {}(ms)", request.getRemoteHost(), 
request.getMethod(),
                    request.getRequestURI(), response.getStatus(), 
processingTime);
    }
}

Upvotes: 2

Views: 1728

Answers (1)

Ken Bekov
Ken Bekov

Reputation: 14015

In Spring you have two options for handling HTTP request/response. These are using of servlet filter (as you do) or interceptor (link).

Filter can change request/response or even stop HTTP workflow at all. If you got unhandled exception in filter, your request stops working.

Interceptor can't change request/response. It can just listen. Unlike filter if you got unhendled exception in interceptor request doesn't stop working (you just get message in console or log).

Concerning URL pattern: it has very simple syntax. In fact almost all you can do is specifying asterisk at the start or end of the string. *.ext - means files with ext extension. /api/* - means everything starts with /api/. I guess this simplicity made in purpose of performance efficiency. But it doesn't fit your requirements.

There is nothing wrong you use regexp in your filter. It won't affect performance significantly. Everything is OK except of one remark. Regular expression processing consist of two parts: compiling of regexp and matching a string. getRequestURI().matches() does the both parts every time you call it. It would be better to compile regexp just once. Add to your filter:

private static Pattern pattern = Pattern.compile(".*/api/.*");

Then you can use precompiled pattern in filter's method:

@Override
public final void doFilterInternal(
    HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
    ...
    if (pattern.matcher(request.getRequestURI()).matches()) {
        //process query
    }   
}

This approach allows to avoid recompilation of pattern every time you use it.

Upvotes: 2

Related Questions