0

I am on a team developing a single page web application with an associated REST API.

I wonder if anyone can help me? I am trying to find a way for our application to return the contents of index.html with a 200 response if certain URLs are accessed. For example the client wants to embed information in the URL but expects the content on index.html to be returned.

For example our single page web application is available on a single context root e.g: http://host:9082/webapp

We have rest endpoints available on http://host:9082/webapp/api/... These endpoints must not return index html, they must only return valid rest responses with the appropriate status code (400, 404, 200, 201 etc)

Java script is served from http://host:9082/webapp/js/... and there are other locations we don't want to fall back to index.html

However, if the client requests http://host:9082/webapp/resource/7/show we want index.html to be returned with status code 200. The client will then extract meaning from the URL to drive other REST requests.

So I tried to write a filter like the following:

@Override
public void doFilter(ServletRequest servletRequest,ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
{
    final HttpServletRequest request = (HttpServletRequest)servletRequest;
    final HttpServletResponse response = (HttpServletResponse)servletResponse;
    final String requestUri = request.getRequestURI();
    if (!excluded(requestUri))
    {
        request.getRequestDispatcher(INDEX_HTML).forward(request, response);
    }
    else
    {
        filterChain.doFilter(servletRequest, servletResponse);
    }
}

private boolean excluded(String requestUri)
{
    for (String part : mExcludedUriParts)
    {
        if (requestUri.contains(part))
        {
            return true;
        }
    }
    return false;
}

and enabled the filter in web.xml as following:

<filter>
    <filter-name>FallbackFilter</filter-name>
    <filter-class>com....http.filter.internal.FallbackFilter</filter-class>
    <init-param>
        <param-name>excludedUriParts</param-name>
        <param-value>/api/,.js/,.png,.html,/apidocs/,/users/imgs/</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>FallbackFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

However this approach is quite fragile as the deployed needs to change the web.xml to match the available resources on the server which may of course change.

We also considered detecting 404's in the filterChain then modifying the response but Liberty did not allow this as the response has already been committed. We also considered using the request accept headers (i.e text/html) as the basis for whether or not to return index html, but we have other html files so this approach did not work either.

We basically want a way to allow some non existent locations on the server to return index.html with a 200 status code. Ideally we want to be informed of a 404 and control the response.

Is there a way to achieve this using filters or any other mechanism in Liberty?

Many thanks

Andy Guibert
  • 41,446
  • 8
  • 38
  • 61

1 Answers1

0

I'm not certain of this, but if you wrap the response in a ServletResponseWrapper you may be able to intercept PrintWriter.flush() so setting the 404 does not commit the response, then the filter can work with it. There's an example of this used for something else here:

https://www.ibm.com/support/knowledgecenter/SSAW57_8.5.5/com.ibm.websphere.nd.iseries.doc/ae/twbs_jaxrs_handlers_servlet_filters.html

Bruce T.
  • 992
  • 4
  • 5
  • Hi! Thanks for your input. I had a look at this method, but I need to apply a filter outside of REST and therefore outside of JaxRS. Also the filter mappings are causing me problems as I want to have other filters run on the REST resources, ("/api/*") but I want this filter to run over anything else, (effectively URIs NOT matching "/api/*). – Martin Feb 20 '18 at 09:41