理論的には、history.pushStateを介してナビゲーションを処理するには、未処理のリソースに対してindex.htmlを返します。最新のWebフレームワークの公式ドキュメントを見ると、404ステータスに基づいて実現されていることがよくあります。
春には、次の順序でリソースを処理する必要があります。
- パスマップされたRESTコントローラー
- アプリの静的リソース
- 他の人のためのindex.html
これを行うには、少なくとも4つの可能な解決策があります。
EmbeddedServletContainerCustomizerとカスタム404ハンドラーの使用
@Controller
static class SpaController {
@RequestMapping("resourceNotFound")
public String handle() {
return "forward:/index.html";
}
}
@Bean
public EmbeddedServletContainerCustomizer containerCustomizer() {
return container -> container.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/resourceNotFound"));
}
カスタムのデフォルトのリクエストマッピングハンドラーを使用する
@Autowired
private RequestMappingHandlerMapping requestMappingHandlerMapping;
static class SpaWithHistoryPushStateHandler {
}
static class SpaWithHistoryPushStateHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(final Object handler) {
return handler instanceof SpaWithHistoryPushStateHandler;
}
@Override
public ModelAndView handle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) throws Exception {
response.getOutputStream().println("default index.html");
return null;
}
@Override
public long getLastModified(final HttpServletRequest request, final Object handler) {
return -1;
}
}
@Bean
public SpaWithHistoryPushStateHandlerAdapter spaWithHistoryPushStateHandlerAdapter() {
return new SpaWithHistoryPushStateHandlerAdapter();
}
@PostConstruct
public void setupDefaultHandler() {
requestMappingHandlerMapping.setDefaultHandler(new SpaWithHistoryPushStateHandler());
}
カスタムResourceResolverの使用
@Autowired
private ResourceProperties resourceProperties;
@Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations(resourceProperties.getStaticLocations())
.setCachePeriod(resourceProperties.getCachePeriod())
.resourceChain(resourceProperties.getChain().isCache())
.addResolver(new PathResourceResolver() {
@Override
public Resource resolveResource(final HttpServletRequest request, final String requestPath, final List<? extends Resource> locations, final ResourceResolverChain chain) {
final Resource resource = super.resolveResource(request, requestPath, locations, chain);
if (resource != null) {
return resource;
} else {
return super.resolveResource(request, "/index.html", locations, chain);
}
}
});
}
カスタムErrorViewResolverの使用
@Bean
public ErrorViewResolver customErrorViewResolver() {
final ModelAndView redirectToIndexHtml = new ModelAndView("forward:/index.html", Collections.emptyMap(), HttpStatus.OK);
return (request, status, model) -> status == HttpStatus.NOT_FOUND ? redirectToIndexHtml : null;
}
概要
4番目のオプションは最も単純に見えますが、いつものように、必要なものによって異なります。また、リクエストがtext / htmlを期待している場合にのみindex.htmlを返すように制限することもできます(BasicErrorControllerは「produces」ヘッダーに基づいてすでに実行しています)。
このオプションの1つがあなたのケースに役立つことを願っています。