How to replace Blazor default "soft 404" with an actual 404 status code response - http-status-code-404

The default Blazor approach to 404 is to create a soft 404 in App.razor, but I would like to adhere to search engine best practices to actually return the 404 status code while displaying a 404 page on Azure.
I tried to remove the element in App.razor to see if I could force a 404, however, that did not compile.
Any suggestions?

I use this code. It works well.
I created Error404Layout. I use this layout for NotFound part.
<Router AppAssembly="#typeof(Program).Assembly" PreferExactMatches="#true">
<Found Context="routeData">
<RouteView RouteData="#routeData" DefaultLayout="#typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="#typeof(Error404Layout)">
<h2>Oops! That page can't be found.</h2>
</LayoutView>
</NotFound>
Error404Layout content below
#inherits LayoutComponentBase
#using Microsoft.AspNetCore.Http
#inject IHttpContextAccessor httpContextAccessor
#Body
#code {
protected override void OnInitialized()
{
httpContextAccessor.HttpContext.Response.StatusCode = 404;
}
}
You have to add this code in startup.cs / services method
public void ConfigureServices(IServiceCollection services)
{
....
services.AddHttpContextAccessor();
}
I can see 404 status code

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-3.1 does state:
Additionally, again for security reasons, you must not use
IHttpContextAccessor within Blazor apps. Blazor apps run outside of
the context of the ASP.NET Core pipeline and the HttpContext isn't
guaranteed to be available within the IHttpContextAccessor, nor it is
guaranteed to be holding the context that started the Blazor app.
So you need to create a wrapper around IHttpContextAccessor to limit this when Blazor is being server side prerendered.
I was able to return 404 http status codes when using server side prerendering in the Blazor WebAssembly App (ASP.Net Core Hosted) Template
When I pointed the browser to http://localhost/fetchdata it returned a page. I wanted this to return a 404 status code as an example. This was possible using dependency injection and a stub class.
In BlazorApp1.Client I added a IResponse.cs file:
namespace BlazorApp1.Client {
public interface IResponse {
void SetNotFound();
}
}
In BlazorApp1.Client I added a ResponseStub.cs file:
namespace BlazorApp1.Client {
public class ResponseStub : IResponse {
public void SetNotFound() {
// Do nothing if we are browser side
}
}
}
In FetchData.razor in BlazorApp1.Client I added:
#inject BlazorApp1.Client.IResponse Response
and in the code section:
protected override void OnInitialized() {
Response.SetNotFound();
}
In Program.cs in BlazorApp1.Client I added:
builder.Services.AddScoped<IResponse, ResponseStub>();
Then in BlazorApp1.Server, in Startup.cs I added under ConfigureServices:
services.AddHttpContextAccessor();
services.AddScoped<IResponse, Response>();
and under Configure I replaced:
endpoints.MapFallbackToFile("index.html");
with:
endpoints.MapFallbackToPage("/_Host");
Then create the Server implementation of IResponse in Response.cs:
using BlazorApp1.Client;
using Microsoft.AspNetCore.Http;
using System.Net;
namespace BlazorApp1.Server {
public class Response : IResponse {
private readonly IHttpContextAccessor _httpContextAccessor;
public Response(IHttpContextAccessor accessor) {
_httpContextAccessor = accessor;
}
public void SetNotFound() {
_httpContextAccessor.HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound;
}
}
}
And finally I create a _Host.cshtml file in BlazorApp1.Server/Pages:
#page "/fallback"
#namespace BlazorPrerendering.Server.Pages
#using BlazorApp1.Client
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
#{
Layout = "_Layout";
}
<app>
<component type="typeof(App)" render-mode="ServerPrerendered" />
</app>
<div id="blazor-error-ui">
An unhandled error has occurred.
Reload
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.webassembly.js"></script>

#ergin-Çelik Your solution works very well. I only had to add the following check because I got an error that the response had already been sent.
I have add this as answer because code formatting is better here.
protected override void OnInitialized()
{
if (_httpContextAccessor.HttpContext != null &&
!_httpContextAccessor.HttpContext.Response.HasStarted)
{
_httpContextAccessor.HttpContext.Response.StatusCode = (int) HttpStatusCode.NotFound;
}
}

Related

Spring Boot + React all pages return 404 except index [duplicate]

I have a single page Angular app with Spring Boot. It looks like the following:
src
main
java
controller
HomeController
CustomerController
OtherController
webapp
js/angular-files.js
index.html
Spring boot correctly defaults to webapp folder and serves index.html file.
What I am looking to do is:
For every local REST request not starting with /api overwrite and redirect to default webapp/index.html. I plan to serve anything /api to the spring controllers.
Is there a way to prefix all controllers with API so that I do not have to write API every time?
e.g.
#RequestMapping("/api/home") can write shorthand in code #RequestMapping("/home")
or
#RequestMapping("/api/other-controller/:id") can write shorthand #RequestMapping("/other-controller/:id")
I'm looking for every API request, e.g. 1) http://localhost:8080/api/home keep API with API and resolve to correct controller and return JSON, however if someone enters a URL like http:///localhost/some-url or http:///localhost/some-other/123/url then it will serve the index.html page and keep the URL.
Alternative ways to do it: try adding #ErrorViewResolver:
Springboot/Angular2 - How to handle HTML5 urls?
If you're tired of trying to solve this problem by following so many conflicting solutions - look here!!
After hours upon hours trying to follow all the scattered advice from dozens of stack overflow and blog posts, I've finally found the minimum PURE spring boot + angular 6 application to always redirect to index.html after a refresh on a non-root page WHILE maintaining all your REST API endpoint paths. No #EnableWebMvc, no #ControllerAdvice, no changes to application.properties, no custom ResourceHandlerRegistry modifications, just simplicity:
Very important pre-requisite
You *must* include the output of ng build into Spring's resources/static folder. You can accomplish this via the maven-resources-plugin. Learn here: Copying multiple resource directories to independent target directories with maven
Code
#Controller
#SpringBootApplication
public class MyApp implements ErrorController {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
private static final String PATH = "/error";
#RequestMapping(value = PATH)
public String error() {
return "forward:/index.html";
}
#Override
public String getErrorPath() {
return PATH;
}
}
Reasoning
Including the output of ng-build into resources/static at build time allows spring view redirects ("forward:/index.html") to succeed. It seems spring cannot redirect to anything outside of the resources folder so if you're trying to access pages at the root of the site, it won't work.
With default functionality (i.e. no additions of #EnableWebMvc or changes to application.properties) navigating to / automatically serves the index.html (iff it was included in the resources/static folder) so no need to make changes there.
With default functionality (as stated above), any error encountered in a spring boot app routes to /error and implementing ErrorController overrides that behavior to - you guessed it - route to index.html which allows Angular to take over the routing.
Remarks
Don't settle for the HashLocationStrategy to get over this problem as it is not recommended by Angular: https://angular.io/guide/router#which-strategy-is-best
For every local REST request not starting with /api overwrite and redirect to default webapp/index.html. I plan to serve anything /api to the spring controllers.
Update 15/05/2017
Let me re-phrase your query for other readers. (Correct me, if misunderstood)
Background
Using Spring Boot and Serving static resources from classpath
Requirement
All 404 non api requests should be redirected to index.html.
NON API - means Requests in which URL doesn't start with /api.
API - 404 should throw 404 as usual.
Sample Response
/api/something - will throw 404
/index.html - will server index.html
/something - will redirect to index.html
My Solution
Let the Spring MVC throw exceptions, if any handler is not available for the given resource.
Add following to application.properties
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
Add a ControllerAdvice as follows
#ControllerAdvice
public class RedirectOnResourceNotFoundException {
#ExceptionHandler(value = NoHandlerFoundException.class)
public Object handleStaticResourceNotFound(final NoHandlerFoundException ex, HttpServletRequest req, RedirectAttributes redirectAttributes) {
if (req.getRequestURI().startsWith("/api"))
return this.getApiResourceNotFoundBody(ex, req);
else {
redirectAttributes.addFlashAttribute("errorMessage", "My Custom error message");
return "redirect:/index.html";
}
}
private ResponseEntity<String> getApiResourceNotFoundBody(NoHandlerFoundException ex, HttpServletRequest req) {
return new ResponseEntity<>("Not Found !!", HttpStatus.NOT_FOUND);
}
}
You can customize the error message as you like.
Is there a way to prefix all controllers with api so that I do not have to write api every time.
For this, you can create a BaseController and set the RequestMapping path to /api
Example
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RequestMapping("/api")
public abstract class BaseController {}
And extend this BaseController and make sure you do not annotate child class with #RequestMapping
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class FirstTestController extends BaseController {
#RequestMapping(path = "/something")
public String sayHello() {
return "Hello World !!";
}
}
Previous Answer
You can create a Filter which redirects to /index.html if request path doesn't startsWith /api.
// CODE REMOVED. Check Edit History If you want.
Try this instead
#SpringBootApplication
#Controller
class YourSpringBootApp {
// Match everything without a suffix (so not a static resource)
#RequestMapping(value = "/**/{path:[^.]*}")
public String redirect() {
// Forward to home page so that route is preserved.(i.e forward:/intex.html)
return "forward:/";
}
}
#Controller
public class RedirectController {
/*
* Redirects all routes to FrontEnd except: '/', '/index.html', '/api', '/api/**'
*/
#RequestMapping(value = "{_:^(?!index\\.html|api).*$}")
public String redirectApi() {
return "forward:/";
}
}
Too late on this thread, but thought it might help someone
Tried many solutions, but this looked pretty straight forward and great to me
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.resource.PathResourceResolver;
import java.io.IOException;
#Configuration
public class MvcConfiguration implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/static/")
.resourceChain(true)
.addResolver(new PathResourceResolver() {
#Override
protected Resource getResource(String resourcePath, Resource location) throws IOException {
Resource requestedResource = location.createRelative(resourcePath);
return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
: new ClassPathResource("/static/index.html");
}
});
}
}
Credits: https://keepgrowing.in/java/springboot/make-spring-boot-surrender-routing-control-to-angular/
The solution that works to me is to overwrite the BasicErrorController of Spring Boot:
#Component
public class CustomErrorController extends BasicErrorController {
public CustomErrorController(ErrorAttributes errorAttributes) {
super(errorAttributes, new ErrorProperties());
}
#RequestMapping(produces = "text/html")
#Override
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
HttpStatus status = getStatus(request);
if (status == HttpStatus.NOT_FOUND) {
return new ModelAndView("forward:/");
} else {
return super.errorHtml(request, response);
}
}
}
The method errorHtml only intercepts not found requests and is transparent for responses 404 (not found) from the api.
Most reasonable solution, imho, for Spring Boot 2+ (code is in Kotlin):
#Component
class ForwardErrorsToIndex : ErrorViewResolver {
override fun resolveErrorView(request: HttpServletRequest?,
status: HttpStatus?,
model: MutableMap<String, Any>?): ModelAndView {
return ModelAndView("forward:/index.html")
}
}
For whole application, you can add context path in application.properties
server.contextPath=/api
It will append "/api" to every requested URL after http://localhost:8080/api/home
For Redirection,
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController("/", "/home");
registry.setOrder(Ordered.HIGHEST_PRECEDENCE);
super.addViewControllers(registry);
}
Put this bunch of code in WebMVCConfig.java
In the #Configuration bean you can add a ServletRegistrationBean to make the spring server for the /api/* resquest only, then in the Controller you don't need to add it.
#Bean
public ServletRegistrationBean dispatcherRegistration() {
ServletRegistrationBean registration = new ServletRegistrationBean(
dispatcherServlet());
registration.addUrlMappings("/api/*");
registration.setLoadOnStartup(1);
registration.setName("mvc-dispatcher");
return registration;
}
I don't know why, but the root url "/" would not resolve without adding a little more code. This is what I ended up with.
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.http.CacheControl;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.resource.PathResourceResolver;
#EnableWebMvc
#Configuration
public class MvcConfiguration implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/")
.addResourceLocations("classpath:/static/")
.resourceChain(true)
.addResolver(new PathResourceResolver() {
#Override
protected Resource getResource(String resourcePath, Resource location) throws IOException {
Resource requestedResource = location.createRelative(resourcePath);
return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
: new ClassPathResource("/static/index.html");
}
});
registry.addResourceHandler("/**/*")
.addResourceLocations("classpath:/static/")
.resourceChain(true)
.addResolver(new PathResourceResolver() {
#Override
protected Resource getResource(String resourcePath, Resource location) throws IOException {
Resource requestedResource = location.createRelative(resourcePath);
return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
: new ClassPathResource("/static/index.html");
}
});
}
}
Ok, let's start with the simple part of your question:
Is there a way to prefix all controllers with api so that I do not have to write api every time?
The answer is yes, just mark your controller with a "global" #RequestMapping annotation, for example:
#RestController
#RequestMapping("/api")
public class ApiController{
#RequestMapping("/hello")
public String hello(){
return "hello simple controller";
}
#RequestMapping("/hello2")
public String hello2(){
return "hello2 simple controller";
}
}
In the example above you can invoke hello method with this URL: /api/hello
and the second method with this URL: /api/hello2
This is how I didn't have to mark each method with /api prefix.
Now, to the more complex part of your question:
is how to achieve a redirect if the request doesn't start with /api prefix?
You can do it by returning an HTTP status code (302) of Redirect, after all, angularJs "speaks" REST natively, thus you can't force a redirect from Java/Spring code like you use to.
Then just return an HTTP message with the status code of 302, and on your angularJS do the actual redirection.
For example:
On AngularJS:
var headers = {'Content-Type':'application/json', 'Accept':'application/json'}
var config = {
method:'GET'
url:'http://localhost:8080/hello',
headers:headers
};
http(config).then(
function onSuccess(response){
if(response.status == 302){
console.log("Redirect");
$location("/")
}
}, function onError(response){
console.log("An error occured while trying to open a new game room...");
});
On Spring:
#RestController
#RequestMapping("/api")
public class ApiController{
#RequestMapping("/hello")
public ResponseEntity<String> hello(){
HttpHeaders header = new HttpHeaders();
header.add("Content-Type", "application/json");
return new ResponseEntity<String>("", header, HttpStatus.FOUND);
}
}
of course, you'll need to custom it to your project.
All you need to try is put the index.html to src/main/resources/static/
See Example: https://github.com/reflexdemon/shop/tree/master/src/main/resources/static
In my package.josn I try to copy it to this location.
See PackageJSON: https://github.com/reflexdemon/shop/blob/master/package.json#L14

Fallback to react application from Spring Controller

I tried many solution and stackoverflow is last place that I can ask about my problem.
I've created application with Spring Boot on backend that also serves my frontend.
My HomeController looks as follows
#Controller
public class HomeController {
#RequestMapping(value = "/*", method={RequestMethod.GET, RequestMethod.HEAD})
public String fallback() {
return "index";
}
}
And here are some antMatchers:
http.csrf().disable()
.authorizeRequests()
.antMatchers("/resources/**", "/built/**").permitAll()
.antMatchers("/css/**").permitAll()
.antMatchers(HttpMethod.POST, "/login").permitAll()
.antMatchers("/registration","/about","/garages/**/*").permitAll()
.antMatchers("/", "/home").permitAll()
Everything works perfect when I'm trying to reach
/registration, /about or just /
but when I'm trying to get
/garages/5
I see empty page and in Network Tab (in mozilla) it show that bundle is trying be taken from
http://localhost:8080/garages/built/bundle.js And status 404
Which for /about page it looks as follows:
http://localhost:8080/built/bundle.js (this is correct one).
Is anybody here able to point any issue that I'm constantly somehow ommitting which causes my problem with proper redirection?
EDIT
If you have your static assets on the resources/static folder, this works:
#Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**/*")
.addResourceLocations("classpath:/static/")
.resourceChain(true)
.addResolver(new PathResourceResolver() {
#Override
protected Resource getResource(String resourcePath, Resource location) throws IOException {
Resource requestedResource = location.createRelative(resourcePath);
return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
: new ClassPathResource("/static/index.html");
}
});
}
}
Solution credits and further explanation:
https://stackoverflow.com/a/46854105

Spring-boot application not finding index.html

I am wiring a AngularJS and spring-boot application together by hand for the first time. The issues I am running into is my #RestController is not returning the index page:
#RestController
public class IndexController {
#RequestMapping("/")
public String index(){
System.out.println("Looking in the index controller.........");
return "index";
}
}
Directory:
It keeps rendering the default 404 error page:
----------------UPDATE 1------------------
I have added a configuration file:
#Configuration
public class IndexPageConfiguration {
#Bean
public InternalResourceViewResolver viewResolver(){
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/app/");
resolver.setSuffix(".html");
return resolver;
}
}
RestController
#RestController
public class IndexController {
#RequestMapping("/")
public String index(){
System.out.println("Looking in the index controller.........");
return "index";
}
}
main class:
#SpringBootApplication(scanBasePackages = { "com.serviceImpl","com.service","com.config" },exclude = { ErrorMvcAutoConfiguration.class })
public class SpringCrudApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCrudApplication.class, args);
}
}
The above main class is still returning the default 404 error page.
On the other hand, Spring will automatically look for the index.html page if you put it directly under webapp folder. So you don't need any configuration.
This is just another way to do it.
You need to configure InternalRosourceViewResolver to let the spring know your jsp location
#Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/app/");
resolver.setSuffix(".html");
return resolver;
}
So Spring will append and append location and suffix to your View returned.
I think it is good idea to keep your views separately in any other folder and configure your folder location according to it.
If you want to continue with your current set up
you should return "/app/index.html" from your controller.
Spring boot provides White label error page to hide your stack trace when a Server side error/ exception occurs, this will help us from protecting our code from intruders.
If you want to get rid of white label error.
In your #SpringBootApplication specify excludes ErrorMvcAutoConfiguration.class
#SpringBootApplication(scanBasePackages = { "com.ekart.app" }, exclude = { ErrorMvcAutoConfiguration.class })
If you are not using #SpringBootApplication annotatio, you should supply same same excludes in #EnableAutoConfiguration annotation

Getting a XMLHttpRequest: Network Error 0x80070005, Access is denied

I have a token endpoint that is passed a username and password grant type to authenticate users. This token endpoint is called from an AngularJS service that is part of my MVC web front end. When I call the service I get the following error
XMLHttpRequest: Network Error 0x80070005, Access is denied.
This seems to be a CORS problem. I did the following to resolve this problem with no luck thus far
I added the app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); to my Startup.cs file for my token web service.
public class Startup
{
public void Configuration
(
IAppBuilder app
)
{
ConfigureOAuth(app);
var config = new HttpConfiguration();
WebApiConfig.Register(config);
config.Filters.Add(new AuthorizeAttribute());
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
private void ConfigureOAuth
(
IAppBuilder app
)
{
app.UseOAuthAuthorizationServer(new OAuthServerOptionsProvider().Provide());
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
I also have a class that is overriding the OAuthAuthorizationServerProvider, within the GrantResourceOwnerCredentials method I have the following code to add all origins to the response headers
public override async Task GrantResourceOwnerCredentials
(
OAuthGrantResourceOwnerCredentialsContext context
)
{
System.Web.HttpContext.Current.Response.Headers.Add("Access-Control-Allow-Origin", "*");
// Other code left out to keep this short
}
In fiddler I can see that the response header was successfully added
Is there something I'm missing here?
Update
Here is my request headers
First of all I have to point out that the comments made by #maurycy helped me find the solution in the comments of this stackoverflow post.
This post explains that the app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); in the Startup.cs file should be moved to the top of the method and that the System.Web.HttpContext.Current.Response.Headers.Add("Access-Control-Allow-Origin", "*"); should be removed from the GrantResourceOwnerCredentials class. So I changed the code in my question to look something like this,
public class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
var config = new HttpConfiguration();
WebApiConfig.Register(config);
config.Filters.Add(new AuthorizeAttribute());
app.UseWebApi(config);
}
private void ConfigureOAuth(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseOAuthAuthorizationServer(new OAuthServerOptionsProvider().Provide());
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
I also have changed the class that is overriding the OAuthAuthorizationServerProvider
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
// Remove the response header that was added
// Other code left out to keep this short
}

Spring MVC: How to map server unknown URLs to the main application page?

We're using angular-route to map URLs to templates. The application works in a way that if for e.g. we're navigating from http://servername/appName to http://servername/appName/page1, the URL on the browser changes and the templates loads successfully.
The problem is that when the page is refreshed (or accessing directly http://servername/appName/page1), we're getting 404 error from the server. It seems like the default handler does not map unknown URLs to the default app page.
How can we make make the server return the default app page for all these angularjs URLs?
The code is below:
#Controller
public class HomeController {
#RequestMapping("/")
public String home() {
return "/WEB-INF/views/nbcalendar.html";
}
}
app configuration:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = {"com.appname.web"})
public class MvcConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
You can set a error handler in the web.xml configuration. Note! This web.xml configures your app inside the Servlet container (E.G. tomcat), it's not a Spring-MVC setting.
Add something like:
<error-page>
<error-code>404</error-code>
<location>/MY_HANDLER</location>
</error-page>
Where MY_HANDLER either is your default location, or something like a jsp that logs the event then forwards to the default location.
Hope that helps.
You can use wildcard expressions in your #RequestMapping to match your application and all it's subpages.
#RequestMapping("/**")
public String home() {
return "/WEB-INF/views/nbcalendar.html";
}
I was able to resolve it by adding the additional URLs to the home controller:
#Controller
public class HomeController {
private static String DEFUALT_PAGE = "/WEB-INF/views/main.jsp";
#RequestMapping("/")
public String home() {
return DEFUALT_PAGE;
}
#RequestMapping("/welcome")
public String welcome() {
return DEFUALT_PAGE;
}
#RequestMapping("/cluster/{id}")
public String cluster() {
return DEFUALT_PAGE;
}
}
This isn't a generic solution and requires to add any new URL manually, but it's working well

Resources