修复由 java servlet 服务的 HTML 中的相对路径(针对 HTML5 pushstate)

Fix relative paths in HTML served by java servlet (for HTML5 pushstate)

我正在尝试修改具有 servlet (RootResource.java) 的 Jetty 服务器,它以某种方式神奇地获取并使用:

@Singleton
@Path("/")
public class RootResource {
    @Context
    private ServletContext servletContext;

    @GET
    @Path("react-client/{path: .*\..+$}")
    public Response serveReactClientContent(@Context HttpServletRequest httpServletRequest) {
        // This doesn't work, a resolved relative resource is not relative
        // to the /react-client base. See description of problem.
        final String pathToResource = httpServletRequest.getRequestURI();
        return serveStaticContent(pathToResource);
    }

    @GET
    @Path("react-client/{path: .*$}")
    public Response serveReactClientIndexPage(@Context HttpServletRequest httpServletRequest) {
        return serveStaticContent("/react-client/index.html");
    }

    private Response serveStaticContent(String pathToResource) {
        final String type = this.servletContext.getMimeType(pathToResource);
        final Response.ResponseBuilder response = Response.ok(servletContext.getResourceAsStream(pathToResource)).type(type);
        return response.build();
    }
}

想法是对 react-client/some/path 和 return react-client/index.html 的内容进行 GET 请求。本质上使 Jetty 表现得像一个使用客户端路由的 webapp 服务器。

我遇到的问题是 index.html 中的相对路径仅在路径深度为一级时才有效 例如react-client/products.

<script src="./webapp.js"></script>

在这种情况下,在 index.html 中找到了上面的 javascript 文件,因为 webapp.js 是一个存在于 react-client/webapp.js.

的文件

一旦我尝试更深入 link 例如react-client/products/97357361 失败,因为 servlet 试图在 react-client/products/webapp.js 中查找不存在的 webapp.js

如何让它始终像来自 /react-client 一样请求资源?谢谢

我尝试了很多东西,比如过滤器和 rewrite handlers 但 Jetty 从来没有提供过原始未解析的相对导入(例如 ./webapp)所以我从来没有机会重写相对资源。

最后我不得不用黑客来检测它们,因为我知道它们几乎都是从 /static/ 子目录请求的(我不得不为 favicon.ico 添加一个硬编码异常和 manifest.json.

@GET
@Path("react-client/{path: .*\..+$}")
public Response serveReactClientContent(@Context HttpServletRequest httpServletRequest) {
    final String pathToResource = httpServletRequest.getRequestURI();

    Pattern p = Pattern.compile("/react-client/(.+?(?=static/|favicon.ico))", Pattern.CASE_INSENSITIVE);
    Matcher m = p.matcher(pathToResource);
    String resolveResourcePath = m.replaceAll("/react-client/");
    return serveStaticContent(resolveResourcePath);
}

对它不满意,但它有效。

因为您的 index.html 可以被多个 url 访问,例如

  • /react-client/products
  • /react-client/products/97357361
  • /react-client/some
  • /react-client/some/路径

在 HTML 页面的 header 添加一个 <base> 标签可能是明智的。

<head>
    ...
    <base href="https://www.yourwebsite.com/react-content/" />
    <script src="./script.js"></script>
    ...
</head>

这将告诉浏览器将页面中找到的任何相对路径解析为相对于 https://www.yourwebsite.com/react-content/

因此,根据上面的示例,<script src="./script.js"></script> 将作为 "https://www.yourwebsite.com/react-content/script.js" 向服务器请求,而不管当前 url 用于访问此页面。

然后,您可以在 Jetty 上还原这些设置并保持简单。