首页 > 解决方案 > 带有 Angular URL 重写的嵌入式 Jetty

问题描述

我正在使用 Jetty 部署 WebSocket 和 Angular 应用程序。在开发中一切正常,但在生产中我遇到的问题是,在刷新前端或输入 url 时,我从服务器收到一个 404,表明给定的资源不存在。现在我正在尝试创建一个重写规则来将请求重定向到我的 index.html。初始化我的服务器如下所示:

server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(config.getServer().getPort());
server.addConnector(connector);

RewriteHandler rewriteHandler = new RewriteHandler();
rewriteHandler.setRewriteRequestURI(true);
rewriteHandler.setRewritePathInfo(false);
rewriteHandler.setOriginalPathAttribute("requestedPath");

/* 
RedirectRegexRule rule1 = new RedirectRegexRule();
rule1.setRegex("/(.+)");
rule1.setLocation("/index.html");

rewriteHandler.addRule(rule1);
*/

URL webRootLocation = this.getClass().getResource("/frontend/index.html");
if (webRootLocation == null)
    throw new IllegalStateException("Unable to determine webroot URL location");

URI webRootUri = URI.create(webRootLocation.toURI().toASCIIString().replaceFirst("/index.html$","/"));
logger.debug("Web Root URI: {}",webRootUri);

ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
contextHandler.setContextPath("/");
contextHandler.setBaseResource(Resource.newResource(webRootUri));
contextHandler.setWelcomeFiles(new String[]{ "index.html" });

rewriteHandler.setHandler(contextHandler);

ServerContainer container = WebSocketServerContainerInitializer.initialize(contextHandler);

List<Class<? extends Encoder>> encoders = new ArrayList<>();
encoders.add(MessageEncoder.class);
List<Class<? extends Decoder>> decoders = new ArrayList<>();
decoders.add(MessageDecoder.class);

ServerEndpointConfig endpointConfig = ServerEndpointConfig.Builder
        .create(AppEndpoint.class, "/wss-test")
        .encoders(encoders)
        .decoders(decoders)
        .configurator(new AppEndpointConfig(config, factory))
        .build();
container.addEndpoint(endpointConfig);

//server.setHandler(contextHandler);
HandlerList handlerList = new HandlerList();
handlerList.setHandlers(new Handler[]{rewriteHandler, contextHandler});
server.setHandler(handlerList);

contextHandler.addServlet(DefaultServlet.class, "/");

server.start();
// server.dump(System.err);
server.join();

我的 Angular 前端编译在应用程序的资源文件夹中,该文件夹由服务器提供服务 - 例如:localhost:8080/. 如果我的应用程序localhost:8080/some/path正常运行,但刷新页面时我得到一个some/path未知的 404。使用重写规则(注释掉)我ERR_TOO_MANY_REDIRECTIONS也找不到延迟加载的资源/模块。关于如何为 Angular 应用程序使用 Jetty 重写的任何建议,因为我没有关于如何在此处继续的胶水,或者 Jetty 不支持angular 部署建议的 apache 重写之类的东西

RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html

标签: javaangularurl-rewritingjettyembedded-jetty

解决方案


对于任何为此寻找解决方案的人,我使它与 Jettys 一起工作RewriteHandler。我的服务器设置现在如下所示:

server = new Server(config.getServer().getPort());

RewriteHandler rewriteHandler = new RewriteHandler();
rewriteHandler.setRewriteRequestURI(true);
rewriteHandler.setRewritePathInfo(false);
rewriteHandler.setOriginalPathAttribute("requestedPath");

RewriteRegexRule rule1 = new RewriteRegexRule();
rule1.setRegex("^((?!"+wsPath+"|\\.js|\\.css|\\.jpe?g|\\.png).)*$");
rule1.setReplacement("/index.html");
rewriteHandler.addRule(rule1);

URL webRootLocation = this.getClass().getResource("/frontend/index.html");
if (webRootLocation == null)
    throw new IllegalStateException("Unable to determine Web-Root URL location");

URI webRootUri = URI.create(webRootLocation.toURI().toASCIIString().replaceFirst("/index.html$","/"));
logger.debug("Web-Root URI: {}",webRootUri);

ServletContextHandler contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
contextHandler.setContextPath("/");
contextHandler.setBaseResource(Resource.newResource(webRootUri));
contextHandler.setWelcomeFiles(new String[]{ "index.html" });

rewriteHandler.setHandler(contextHandler);

// Initialize WebSocket
ServerContainer container = WebSocketServerContainerInitializer.initialize(contextHandler);

List<Class<? extends Encoder>> encoders = new ArrayList<>();
encoders.add(MessageEncoder.class);
List<Class<? extends Decoder>> decoders = new ArrayList<>();
decoders.add(MessageDecoder.class);

ServerEndpointConfig endpointConfig = ServerEndpointConfig.Builder
        .create(AppEndpoint.class, "/" + wsPath)
        .encoders(encoders)
        .decoders(decoders)
        .configurator(new AppEndpointConfig(config, factory))
        .build();
container.addEndpoint(endpointConfig);

server.setHandler(rewriteHandler);

contextHandler.addServlet(DefaultServlet.class, "/");

server.start();
server.join();

这并不理想,因为只有特定的文件结尾与正则表达式匹配,但它确实适用于 Jetty 内构建和部署的 Angular 应用程序。如果使用 RESTful API,则必须定义一些正则表达式以匹配 API 的路径,如wsPath我示例中的(简单字符串)。


推荐阅读