Spark: Enable custom error pages, when deploy Sparkjava embedded by (Jetty)

Created on 22 Sep 2014  路  6Comments  路  Source: perwendel/spark

  • Cannot config custom error pages when deploy SparkJava embedded by Jetty
  • Description:

Jetty 9 config

  • contextPath = "/"
  • jetty base folder
    ......./webapps/
    ................/WEB-INF/
    ................/WEB-INF/lib/
    ................/WEB-INF/web.xml
    ................/errors/
    .........................../404.html
    .........................../500.html
  • web.xml setting custom errors
<error-page>
        <error-code>404</error-code>
        <location>/errors/404.html</location>
</error-page>

When access /not_exists, current 404 error page return by Sparkjava embedded by Jetty is:

HTTP ERROR 404

Problem accessing /errors/404.html. Reason:

    Not Found

Powered by Jetty://

Expectation

Url should redirect from: /not_exists to /errors/404.html

Feature request

Most helpful comment

After spending a few days scraping through the internet, reading jetty documents, and actually read spark's source code, I was able to combine the last comment(by Rob Eden) on this article:
https://gsmblog.net/blog/spark-framework-the-tiny-framework-that-almost-could/
with stuff I learned from jetty and spark, to come up with a work around like this:

public static void main(String[] args) throws Exception {
    // Start can configure Jetty
    Server server = new Server(8080);
    WebAppContext webapp = new WebAppContext();
    webapp.setContextPath("/");
    webapp.setResourceBase("FULL_PATH_TO_MY_STATIC_FILE_FOLDER");

    // Not sure if this is needed, but it worked for me without it 
    //webapp.setWar( "/" );

    // Hooking up Spark
    // The Java equivalent of http://sparkjava.com/documentation.html#other-webserver
    FilterHolder holder = webapp.addFilter(
            SparkFilter.class,
            "/*",
            EnumSet.of(DispatcherType.REQUEST)
    );

    holder.setInitParameter(
            "applicationClass",
            MySparkFilter.class.getName()
    );

    // Setting up your custom error pages
    ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
    // The file is at FULL_PATH_TO_MY_STATIC_FILE_FOLDER/404.html
    errorHandler.addErrorPage(HttpServletResponse.SC_NOT_FOUND, "/404.html");
    webapp.setErrorHandler(errorHandler);

    server.setHandler(webapp);

    // Starting the Server
    server.start();
    System.out.println("Started!");
    server.join();
}

And _MySparkFiter.java_ is like this

public class MySparkFilter implements SparkApplication {
    @Override
    public void init() {
        get("/hello", (req, res) -> "Hello World");
    }
}

So basically I'm starting and configuring the Jetty that comes with Spark, and deploy Spark to it, instead of letting Spark start Jetty with its defaults.

  • Can't believe this issue isn't addressed for almost 2 years
  • I wish I didn't have to read through lengthy Jetty documents and Spark source code to figure this out. It defeats the reason I chose Spark in the first place: clean, simple, and works out of the box. I just want to write my application.
  • I wish Spark could have more detailed documents. If it's not practical for Spark to provide more configuration to the embedded Jetty(which I will highly appreciate), at least provide a bit more documents and examples for work around like this.

All 6 comments

this requires a custom error handler to be installed in order to fix.

question: how put off would you be if you couldn't configure this via the static interface and instead had to use a builder to get a spark instance? eg:

SparkServerBuilder serverBuilder = JettyServerBuilder.builder().<set options>.build();
SparkApi spark = SparkBuilder.build(serverBuilder).<set options>.build();

<setup routes, filters, etc>

spark.start();

I am not sure if it would work like that..

The way it spark works is when there is 404 error, The body content is assigned to NOT_FOUND constant..
I think you can rewrite bodycontent when there is no match in the MatchFilter class. To be more specific, if there is NotConsumedException then we can rewrite the bodyContent and set header as 404. I am not sure if thats the right way to do it. For example,

 if (!consumed && hasOtherHandlers) {
      LOG.info("The requested route [" + uri + "] has not been mapped in Spark");
     httpResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
     bodyContent = String.format(NOT_FOUND);
    consumed = true;
     //  throw new NotConsumedException();
}

NOT_FOUND can be assigned to your custom html code. May be we can have a singleton that reads from resource directory where your custom page exists.

I think this would kinda solve the problem.

After spending a few days scraping through the internet, reading jetty documents, and actually read spark's source code, I was able to combine the last comment(by Rob Eden) on this article:
https://gsmblog.net/blog/spark-framework-the-tiny-framework-that-almost-could/
with stuff I learned from jetty and spark, to come up with a work around like this:

public static void main(String[] args) throws Exception {
    // Start can configure Jetty
    Server server = new Server(8080);
    WebAppContext webapp = new WebAppContext();
    webapp.setContextPath("/");
    webapp.setResourceBase("FULL_PATH_TO_MY_STATIC_FILE_FOLDER");

    // Not sure if this is needed, but it worked for me without it 
    //webapp.setWar( "/" );

    // Hooking up Spark
    // The Java equivalent of http://sparkjava.com/documentation.html#other-webserver
    FilterHolder holder = webapp.addFilter(
            SparkFilter.class,
            "/*",
            EnumSet.of(DispatcherType.REQUEST)
    );

    holder.setInitParameter(
            "applicationClass",
            MySparkFilter.class.getName()
    );

    // Setting up your custom error pages
    ErrorPageErrorHandler errorHandler = new ErrorPageErrorHandler();
    // The file is at FULL_PATH_TO_MY_STATIC_FILE_FOLDER/404.html
    errorHandler.addErrorPage(HttpServletResponse.SC_NOT_FOUND, "/404.html");
    webapp.setErrorHandler(errorHandler);

    server.setHandler(webapp);

    // Starting the Server
    server.start();
    System.out.println("Started!");
    server.join();
}

And _MySparkFiter.java_ is like this

public class MySparkFilter implements SparkApplication {
    @Override
    public void init() {
        get("/hello", (req, res) -> "Hello World");
    }
}

So basically I'm starting and configuring the Jetty that comes with Spark, and deploy Spark to it, instead of letting Spark start Jetty with its defaults.

  • Can't believe this issue isn't addressed for almost 2 years
  • I wish I didn't have to read through lengthy Jetty documents and Spark source code to figure this out. It defeats the reason I chose Spark in the first place: clean, simple, and works out of the box. I just want to write my application.
  • I wish Spark could have more detailed documents. If it's not practical for Spark to provide more configuration to the embedded Jetty(which I will highly appreciate), at least provide a bit more documents and examples for work around like this.

See my proposal for a short term fix for this in #555 It follows the same pattern of Play 1.x where you just drop in a 404.html and a 500.html in your resources folder. If the files aren't present then the default error pages (the ones we see now) are shown.

Added in #719

Was this page helpful?
0 / 5 - 0 ratings