203

How can I use a servlet filter to change an incoming servlet request url from

http://nm-java.appspot.com/Check_License/Dir_My_App/Dir_ABC/My_Obj_123

to

http://nm-java.appspot.com/Check_License?Contact_Id=My_Obj_123

?


Update: according to BalusC's steps below, I came up with the following code:

public class UrlRewriteFilter implements Filter {

    @Override
    public void init(FilterConfig config) throws ServletException {
        //
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) req;
        String requestURI = request.getRequestURI();

        if (requestURI.startsWith("/Check_License/Dir_My_App/")) {
            String toReplace = requestURI.substring(requestURI.indexOf("/Dir_My_App"), requestURI.lastIndexOf("/") + 1);
            String newURI = requestURI.replace(toReplace, "?Contact_Id=");
            req.getRequestDispatcher(newURI).forward(req, res);
        } else {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void destroy() {
        //
    }
}

The relevant entry in web.xml look like this:

<filter>
    <filter-name>urlRewriteFilter</filter-name>
    <filter-class>com.example.UrlRewriteFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>urlRewriteFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

I tried both server-side and client-side redirect with the expected results. It worked, thanks BalusC!

Java_User
  • 1,303
  • 3
  • 27
  • 38
Frank
  • 30,590
  • 58
  • 161
  • 244
  • Related question: http://stackoverflow.com/questions/2723829/how-to-catch-non-exist-requested-url-in-java-servlet – BalusC Apr 27 '10 at 21:06
  • Which version of the servlet spec are you using ? How you forward requests changes with the different versions. – Romain Hippeau Apr 27 '10 at 21:11
  • [See this post](http://stackoverflow.com/questions/2283237/most-useful-java-servlet-filter-out-there) it also has a Filter that does what you want – Romain Hippeau Apr 27 '10 at 21:38
  • Thanks I was searching for an example on url rewriting and encryption . – Aditya Yada Jul 19 '16 at 13:08
  • Please note that if your original URL contains parameters, i.e. http://nm-java.appspot.com/Check_License/Dir_My_App/Dir_ABC/My_Obj_123?**param1=A&param2=B** then these parameters will be also forwarded to next servlet/jsp. I didn't find a way to get rid of or replace original parameters (only by using HttpServletRequestWrapper). Any ideas?.. Update: it seems that [http://ocpsoft.org/opensource/how-to-safely-add-modify-servlet-request-parameter-values/](http://ocpsoft.org/opensource/how-to-safely-add-modify-servlet-request-parameter-values/) addresses this problem. – Lopotun May 17 '12 at 09:41

4 Answers4

294
  1. Implement javax.servlet.Filter.
  2. In doFilter() method, cast the incoming ServletRequest to HttpServletRequest.
  3. Use HttpServletRequest#getRequestURI() to grab the path.
  4. Use straightforward java.lang.String methods like substring(), split(), concat() and so on to extract the part of interest and compose the new path.
  5. Use either ServletRequest#getRequestDispatcher() and then RequestDispatcher#forward() to forward the request/response to the new URL (server-side redirect, not reflected in browser address bar), or cast the incoming ServletResponse to HttpServletResponse and then HttpServletResponse#sendRedirect() to redirect the response to the new URL (client side redirect, reflected in browser address bar).
  6. Register the filter in web.xml on an url-pattern of /* or /Check_License/*, depending on the context path, or if you're on Servlet 3.0 already, use the @WebFilter annotation for that instead.

Don't forget to add a check in the code if the URL needs to be changed and if not, then just call FilterChain#doFilter(), else it will call itself in an infinite loop.

Alternatively you can also just use an existing 3rd party API to do all the work for you, such as Tuckey's UrlRewriteFilter which can be configured the way as you would do with Apache's mod_rewrite.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 1
    Any doFilter() sample code somewhere that does the above ? Thanks. – Frank Apr 27 '10 at 21:21
  • 20
    At what step exactly are you stucking? My answer almost writes code itself. Did you also note that the code references in blue are actually links to Javadocs which describes the class/method behaviour in detail? At any way, you can find [here](http://courses.coreservlets.com/Course-Materials/csajsp2.html) and [here](http://courses.coreservlets.com/Course-Materials/msajsp.html) good JSP/Servlet tutorials, specifically [this](http://courses.coreservlets.com/Course-Materials/pdf/msajsp/05-Filters.pdf) one about filters. – BalusC Apr 27 '10 at 21:26
  • I followed the same for implementing filter but not getting success. Please help. The request is not redirecting to the destination resource class for service. – Kumar Shorav Sep 30 '13 at 11:22
  • @Actually I canot ask question from this account. This is the link for my another account - http://stackoverflow.com/questions/19089186/getting-hostname-of-the-client-that-is-calling-my-jax-rs-rest-webservice sorry for this inconvenience. – Kumar Shorav Sep 30 '13 at 11:27
  • @BalusC I am using filter mechanism for authentication of Host Name for the service caller with the key provided to the caller. here I want to validate the caller and then forwarded to service url requested. Other wise it will return unauthorized exception. Please help me...after googling as lot I found this and then tried this with no success. Please seem my web.xml and also inside doFilter() method. – Kumar Shorav Sep 30 '13 at 12:04
  • 2
    I supose it is correct, but if the filter is one of the firsts in the chain, and `RequestDispatcher#forward()` is executed, the rest of the filters won't be executed. So, won't be a better way then doing this as a servlet? – lucasvc Jan 17 '14 at 08:32
  • 2
    @datakey: just either rearrange the ordering or add `FORWARD` to filter mapping. – BalusC Jan 17 '14 at 10:23
  • 2
    @BalusC can we do it without redirecting or calling forward? – Aman J Jul 28 '15 at 10:03
  • 1
    This solution works, but if we have chains of filters? As I understand this solution ruins the logic of filters - when there are chain of filters and every filter must do something before processing request and after processing request. But this solutions instead forwards request to certain servlet what is not its work. – Pavel_K Jun 15 '16 at 11:45
  • 1
    @JimJim2000: just either rearrange the ordering or add `FORWARD` to filter mapping. – BalusC Jun 15 '16 at 11:46
  • 1
    I've read about FORWARD is not what is suitable for me. And I can't understand how I can rearrange the ordering to get what I say. Because it can be possible only with something like request.setUrl(String newUrl);chain.doFilter(...); – Pavel_K Jun 15 '16 at 11:54
22

You could use the ready to use Url Rewrite Filter with a rule like this one:

<rule>
  <from>^/Check_License/Dir_My_App/Dir_ABC/My_Obj_([0-9]+)$</from>
  <to>/Check_License?Contact_Id=My_Obj_$1</to>
</rule>

Check the Examples for more... examples.

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
10

A simple JSF Url Prettyfier filter based in the steps of BalusC's answer. The filter forwards all the requests starting with the /ui path (supposing you've got all your xhtml files stored there) to the same path, but adding the xhtml suffix.

public class UrlPrettyfierFilter implements Filter {

    private static final String JSF_VIEW_ROOT_PATH = "/ui";

    private static final String JSF_VIEW_SUFFIX = ".xhtml";

    @Override
    public void destroy() {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        HttpServletRequest httpServletRequest = ((HttpServletRequest) request);
        String requestURI = httpServletRequest.getRequestURI();
        //Only process the paths starting with /ui, so as other requests get unprocessed. 
        //You can register the filter itself for /ui/* only, too
        if (requestURI.startsWith(JSF_VIEW_ROOT_PATH) 
                && !requestURI.contains(JSF_VIEW_SUFFIX)) {
            request.getRequestDispatcher(requestURI.concat(JSF_VIEW_SUFFIX))
                .forward(request,response);
        } else {
            chain.doFilter(httpServletRequest, response);
        }
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {

    }

}
Community
  • 1
  • 1
Aritz
  • 30,971
  • 16
  • 136
  • 217
3

In my case, I use Spring and for some reason forward did not work with me, So I did the following:

public class OldApiVersionFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        if (httpServletRequest.getRequestURI().contains("/api/v3/")) {
            HttpServletRequest modifiedRequest = new HttpServletRequestWrapper((httpServletRequest)) {
                @Override
                public String getRequestURI() {
                    return httpServletRequest.getRequestURI().replaceAll("/api/v3/", "/api/");
                }
            };
            chain.doFilter(modifiedRequest, response);
        } else {
            chain.doFilter(request, response);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {}

    @Override
    public void destroy() {}
}

Make sure you chain the modifiedRequest

Youans
  • 4,801
  • 1
  • 31
  • 57
  • Maybe the reason "forrward" didn't fork for you is because it's "forward"... – Pere Jan 12 '23 at 17:09
  • You could have edited the typo overwriting a whole comment line! – Youans Jan 13 '23 at 20:34
  • Doing so would have altered the sense of your reply, Youans, as I couldn't take for granted if it was either a typo while writing your answer or a mistake in the source code you tried. You could have done the proper edit, as you are the only who knows what's the correct case, but you didn't, either. By the way, I made a typo, also, but I cannot fix it. I meant "work" instead of "fork"... d'oh! – Pere Jan 15 '23 at 18:52
  • @Pere it is not in the code! However I see your point, but even if it was code it is not like it was written by a robot – Youans Jan 15 '23 at 21:37
  • This worked for me. Thank you so much.! – R.Wedisa Jul 22 '23 at 12:12