我有使用
history.pushState()
进行导航的 SPA 应用程序,因此我需要为许多 URL 提供相同的 HTML(可能由 JSP 或 servlet 生成)。不过,有些静态资源不能被这种机制“拦截/重写”。我还需要添加仅匹配 HTML 而不是其他静态资源或其他 servlet 的过滤器。最后,这个“转发”必须被范围指定到特定的路径(我的应用程序具有多个此类 SPA,每个 SPA 都有自己的范围和 HTML),而这一切都使用嵌入式 Jetty。
我在 Jetty 9、10 和 11 上都有工作代码,但 Jetty 12 引入了重大更改,使其无法执行。我正在寻找一种方法来使用 Jetty 12 复制相同的行为。
所以,假设这些文件:
/index.html
/subdir/
+- app.js
+- style.css
`- index.html
和 servlet 映射到
/subdir/logout
和 /subdir/api/*
。
我需要所有这些请求返回
/subdir/index.html
(正确地通过具有request或forward调度类型的过滤器):
/subdir/
/subdir/index.html
/subdir/foo
/subdir/foo/bar
/subdir/bar
但是这些应该正确返回静态文件或调用映射的 servlet:
/subdir/app.js
/subdir/style.css
/subdir/api/foo
/subdir/logout
在 Jetty 9/10/11 中,我曾经这样做过(注意:
context
是 ServletContextHandler
):
// Sometimes I need a filter such as this one (injecting HTML/JS into the response)
// or other filters that would redirect unauthenticated users to login (possibly SSO)
context.addFilter(CsrfServletFilter.class, "*.html", EnumSet.of(REQUEST, ASYNC, FORWARD));
// Sometimes the HTML is generated by a servlet (other times it would be an index.jsp file)
context.addServlet(new ServletHolder(indexServlet), "/subdir/index.html");
ServletHolder resources =
new ServletHolder(
"resources",
new DefaultServlet(
new ResourceService() {
@Override
protected void notFound(HttpServletRequest request, HttpServletResponse response)
throws IOException {
// For use with history.pushState: send back the index page for everything not found.
try {
response.setHeader("Content-Location", "/subdir/");
request.getRequestDispatcher("/subdir/").forward(request, response);
} catch (ServletException e) {
throw new RuntimeException(e);
}
}
}));
resources.setInitParameter("dirAllowed", "false");
resources.setInitParameter("welcomeServlets", "exact");
context.addServlet(resources, "/subdir/*");
Jetty 12 更改了大部分
DefaultServlet
API 和内部结构,使得上述内容不再可能。有什么替代方案吗?
根据您所说的,您根本不需要任何复杂的
DefaultServlet
逻辑。
您的代码在 Jetty 9 / 10 / 11 中基本上是无操作并回调自身。 (事实上,在某些情况下,你甚至创建了无限循环)
你需要两件事。
ServletContextHandler
中指定或作为 DefaultServlet 上的 init-param DefaultServlet
的 servlet 上的 servlet 规范正常 default
。您可以选择在不同的基础资源上提供额外的
DefaultServlet
(通过 init-params)
在
jetty-examples
项目中找到了这样的示例。
码头 | 路径 |
---|---|
12号码头 |
|
11号码头 |
|
10号码头 |
|
9号码头 |
|
查看
ServletFileServerMultipleLocations
示例。
如果您选择使用多基础资源方法,您可以简单地使用 Jetty 12 中的资源组合功能。
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
ResourceFactory resourceFactory = ResourceFactory.of(context);
Resource defaultBase = resourceFactory.newClassLoaderResource("/webroot/");
Resource subdirBase = resourceFactory.newClassLoaderResource("/webroot/subdir/");
Resource multiBase = ResourceFactory.combine(defaultBase, subdirBase);
context.setBaseResource(multiBase);
ServletHolder holderDef = new ServletHolder("default", DefaultServlet.class);
holderDef.setInitParameter("dirAllowed", "true");
context.addServlet(holderDef, "/");