How to return a custom 404 or 410 with Spring Boot

Updated:

image for 404 error

Sometimes it happens that the visitor writes incorrectly an URL or the page you created doesn’t exist anymore.

It’s important to return the correct code and if possible an explicit message to the user or to the search engine. 404 and 410 HTTP codes are used by Google search engine to remove old pages from their index. This avoids lowering the quality of your content because your server is showing empty pages or errors.

Here you can find the detail about how to remove permanently a page from Google.

How to return a HTTP 404 (Not found) or HTTP 410 (Gone) with Spring Boot?

If you are using @ResponseBody you can simply declare an exception:

throw new ResponseStatusException( 
  HttpStatus.NOT_FOUND, "the page is not found" 
); 

The NOT_FOUND enumerator returns a 404 error. From the Spring code: NOT_FOUND(404, Series.CLIENT_ERROR, "Not Found”),

By default, throwing ResponseStatusException will escalate the exception to the browser showing and non-user friendly presentation of our error message.

whitelabel error in spring

If you are on this post because of the Whitelabel Error Page deploying an Angular application ... you are in the wrong post and you should go here: https://marmo.dev/angular-spring-whitelabel

How can we avoid the ugly ‘Whitelabel Error Page’?

Spring Boot comes with an easy and smart solution. You can simply add a default page in your static assets with the name 404.html (or 410.html for the GONE HTTP message. Spring will automatically map the 404 error with the 404.html in the assets.

src/ 
 +- main/ 
     +- java/ 
     |   + <source code> 
     +- resources/ 
         +- public/ 
             +- error/ 
             |   +- 404.html 
             +- <other public assets> 

Here you have more details from the official Spring documentation

This path can be customized with the server.error.path Spring property (default: /error)

The whitelabel can be deactivated using properties: server.error.whitelabel.enabled=false

Custom ModelAndView

I prefer to handle the error page as View, if an exception is found in the backend I return a ModelAndView this gives me more flexibility if I want to send parameters (e.g. custom friendly message). Important is to give the HttpStatus.NOT_FOUND, for a ‘human' user the http header is maybe not important but for search engines it's very important and could avoid 'damages' to your SEO.

return new ModelAndView("not-found-page", HttpStatus.NOT_FOUND); 
browser console error

Deep dive into the ‘Whitelabel Error Page’

The properties of the Whitelabel and the error pages can be found here: ErrorProperties.java

This class defines the parameters name to customize the path of the error page and if the Whitelabel error is enabled or not.

The configuration of the Whitelabel is here in ErrorMvcAutoConfiguration.java

@Configuration(proxyBeanMethods = false) 
@ConditionalOnProperty(prefix = "server.error.whitelabel", name = "enabled", matchIfMissing = true) 
@Conditional(ErrorTemplateMissingCondition.class) 
protected static class WhitelabelErrorViewConfiguration { 
 
  private final StaticView defaultErrorView = new StaticView(); 
 
  @Bean(name = "error") 
  @ConditionalOnMissingBean(name = "error") 
  public View defaultErrorView() { 
    return this.defaultErrorView; 
  } 
 
  // If the user adds @EnableWebMvc then the bean name view resolver from 
  // WebMvcAutoConfiguration disappears, so add it back in to avoid disappointment. 
  ... 
} 

The same class contains the implementation as you can see Spring returns a StaticView in other words a Servlet Response (servlet.View):

private static class StaticView implements View 
@Override 
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) 
... 
response.setContentType(TEXT_HTML_UTF8.toString()); 
StringBuilder builder = new StringBuilder(); 
... 
builder.append("<html><body><h1>Whitelabel Error Page</h1>").append( 
"<p>This application has no explicit mapping for /error, so you are seeing this as a fallback.</p>") 
... 
response.getWriter().append(builder.toString());} 
... 

WebApp built by Marco using SpringBoot 3.2.4 and Java 21, in a Server in Switzerland without 'Cloud'.