Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle 404 in application context level

I have 2 applications/projects deployed in tomcat 7 web server. There context paths are different like "project1", "project2". When I hit URLs with these context path, corresponding application loads and works fine.

Valid URLs are:

http://localhost:8080/project1

http://localhost:8080/project2

Now when I hit any wrong URL with correct host name and incorrect context path like /project3, it give me error message 404 not found and shows a weird screen to the user.

I want to show a proper page with proper message to the end user. How can I do that in web server level?

like image 844
Sunil Sharma Avatar asked Oct 19 '22 17:10

Sunil Sharma


2 Answers

You can adapt Tomcat's conf/web.xml file to show some other page than the default for the 404 error - see here for an example.

Extract:

<error-page>  
       <error-code>404</error-code>  
       <location>/NotFound.jsp</location>  
</error-page>
like image 63
Alexander Rühl Avatar answered Oct 22 '22 22:10

Alexander Rühl


In theory, you should be able to modify the web.xml of the default tomcat web application, but according to this, that doesn't work for Tomcat 7.

Your other option is to extend the standard ErrorReportValve. I have "borrowed" very liberally from the existing ErrorReportValve code:

    public class Custom404Valve extends ErrorReportValve{

        public void invoke(Request request, Response response) throws IOException, ServletException {

           if(request.getStatusCode() != 404){
               super.invoke();
               return;
           }
           // Perform the request
           getNext().invoke(request, response);

           if (response.isCommitted()) {
               if (response.setErrorReported()) {
                   try {
                    response.flushBuffer();
                  } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                  }
               response.getCoyoteResponse().action(ActionCode.CLOSE_NOW, null);
                }
          return;
          }

         response.setSuspended(false);
         //this is where your code really matters
         //everything prior are just precautions I lifted
         //from the stock valve. 
         try {
           response.setContentType("text/html");
           response.setCharacterEncoding("utf-8");
           String theErrorPage = loadErrorPage();
           Writer writer = response.getReporter();
           writer.write(theErrorPage);
           response.finishResponse();
         } catch (Throwable tt) {
           ExceptionUtils.handleThrowable(tt);
         }

         if (request.isAsyncStarted()) {
             request.getAsyncContext().complete();
         }
      }

      protected String loadErrorPage() {
          BufferedReader reader = null;
          StringBuilder errorMessage = new StringBuilder();
              try{
                 File file = new File("YourErrorPage.html");
                 reader = new BufferedReader(new FileReader(file));

                    while (reader.ready()) {
                       errorMessage.append(reader.readLine());
                    }
              }catch (IOException e){
                  e.printStackTrace();
              }finally{
                 try{
                    reader.close();
                 }catch (IOException e) {
                    e.printStackTrace();
                 }
              } 
          return errorMessage.toString();     
        }
    }

All you now need do is configure the custom valve:

    <Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true" xmlValidation="false" xmlNamespaceAware="false">

        <Valve className="com.foo.bar.Custom404Valve"/>
    </Host>
like image 29
kolossus Avatar answered Oct 22 '22 22:10

kolossus