我正在使用Spring Boot和Angular 1.5.X构建一个项目,并且正在努力处理Angular路由的整页刷新 - 典型的"404,因为我创建的路径实际上并不存在"问题。我已经做了相当多的研究,我一直看到的解决方案是实现一个带有以下代码片段的 .htaccess 文件,以便将所有未知请求重定向回索引(我从这篇文章中提取了以下内容)
RewriteEngine On
Options FollowSymLinks
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /#/$1 [L]
我已经安装了Tuckey的UrlRewriteFilter - 根据这篇博客文章,因为我没有WEB-INF文件夹 - 它正在工作。它启动并读取 urlrewrite.xml成功。但是,我不知道在我的urlrewrite中放什么.xml - 我对如何将上述内容翻译成UrlRewriteFilter可以理解的内容一无所知。我已经浏览了UrlRewriteFilter的手册,但我真的不知道从哪里/如何开始。
基本上,我必须在 urlrewrite 中放入什么.xml以便如果我按 F5,我的网站不会返回 404 错误?
任何帮助,不胜感激。
编辑 1
我应该提到,我所有的 API 端点都以/api/**
开头,以便将它们与前端的链接区分开来 - 一个例子是/api/open/getUser
和/api/secured/updateSettings
。
编辑 2
到目前为止,我发现了几件事。一个是 UrlRewriteFilter 实际上可以支持 .htaccess 文件,我确实(据我所知)通过将 .htacess 移动到我的资源文件夹中并稍微调整上述博客文章中的代码示例来加载它,更改了这个
private static final String CONFIG_LOCATION = "classpath:/urlrewrite.xml";
自
private static final String CONFIG_LOCATION = "classpath:/.htaccess";
和
Conf conf = new Conf(filterConfig.getServletContext(), resource.getInputStream(), resource.getFilename(), "MyProject");
自
Conf conf = new Conf(filterConfig.getServletContext(), resource.getInputStream(), resource.getFilename(), "MyProject", true);
添加true
会告知筛选器使用 .htaccess 文件。太棒了,问题解决了吧?不完全是 - 这很难解释,但似乎 UrlRewriteFilter 没有正确读取 .htacess。我正在使用 .htacess 测试器来验证正则表达式和重写条件是否按我的预期工作,而且它们似乎是。测试人员说他们很好。但是,UrlRewriteFilter 会吓坏并陷入某种循环中,以至于 Java 会抛出堆栈溢出异常(至于为什么,我不知道 - 我似乎找不到一种方法来设置过滤器的日志记录级别以通过 Java D:<进行调试)。>
很明显,这不起作用 - 我目前正在尝试将 .htaccess 翻译成 urlrewrite.xml我自己,这是我迄今为止设法创建的内容。
<urlrewrite use-query-string="true">
<rule match-type="regex" enabled="true">
<note>
Any URI that ends with one of the following extensions will be allowed to continue on unimpeded.
Buried in the manual was the single line that said a "-" in the "to" will allow the request to
continue on unmodified.
</note>
<from>.(html|css|jpeg|gif|png|js|ico|txt|pdf)$</from>
<to last="true">-</to>
</rule>
<rule match-type="regex" enabled="true">
<note>
Any URI that is prefaced with "/api/open/**" or "/api/secured/**" will be allowed through unmodified.
</note>
<condition type="request-uri" operator="equal">/api/(open|secured)/([a-zA-Z0-9/]+)</condition>
<from>^.*$</from>
<to last="true">-</to>
</rule>
<rule match-type="regex" enabled="false">
<note>
This one is supposed to be a "when all else fail" rule - if the other two rules don't match,
forward to the index and let Angular figure out the rest.
!! This one seems to be getting stuck in a loop of sorts !!
</note>
<from>^.*$</from>
<to last="true">/</to>
</rule>
</urlrewrite>
前两个似乎工作得很好。第三条规则(启用设置为 false 的规则)没有 - 它似乎也卡在与 .htacess 方法相同的过滤器循环中(或正在发生的任何事情 - 堆栈跟踪是如此之大,以至于 Intellij 就像"没有人")。取得进展。
> 胡扎,我设法得到了它!这是一个正确的痛苦,因为我无法弄清楚如何打开调试并查看过滤器实际在做什么,但唉,我成功了!
花了一公制废话大量时间使用正则表达式测试器,这就是我想出的。我甚至离正则表达式大师都远不近,所以如果您有恶心,请尝试控制您的恶心。
<urlrewrite use-query-string="true">
<rule match-type="regex" enabled="true">
<note>
- "/post/**" and "/user/.../**" are optional - this is because when you're on, say, "/post/20" and you hit
F5, the browser will attempt to get the static assets from "/post/**"
- the second group is used to see if the request is for a static asset
- take advantage of back references and forward only the part that matches the second group
- i.e. "/post/20" as URI -> hit F5 -> "/post/scripts/mainController.js" request of server -> "/scripts/mainController.js" forwarded
- i.e. "/user/Tester/home" -> hit F5 -> "/user/Tester/scripts/mainController.js" -> "/scripts/mainController.js" forwarded
</note>
<condition type="request-uri" operator="equal">/?(post/|user/[a-zA-Z0-9]+/)(.*.(html|css|jpe?g|gif|png|js|ico|txt|pdf))</condition>
<from>^.*$</from>
<to last="true">/%2</to>
</rule>
<rule match-type="regex" enabled="true">
<note>
Any URI that is prefaced with "/api/open/**" or "/api/secured/**" will be allowed through unmodified.
</note>
<condition type="request-uri" operator="equal">/api/(open|secured)/([a-zA-Z0-9/]+)</condition>
<from>^.*$</from>
<to last="true">-</to>
</rule>
<rule match-type="regex" enabled="true">
<note>
- Register, browse, search, and upload are all single level urls - the "z" is to match the end of the string,
otherwise "/register" would match "/registerController.js"
- Inbox CAN be like "/inbox/favorites" so that's why it has a secondary regex - my Regex-Fu isn't good enough to combine
- Settings always has a secondary level
- User always has either home, gallery (w/ page and number), or favorites (w/ page and number)
- A post will always have a number
</note>
<condition type="request-uri" operator="equal" next="or">/(registerz|browsez|searchz|uploadz|inboxz|tagz)</condition>
<condition type="request-uri" operator="equal" next="or">/inbox/(favoritesz|uploadsz|commentsz)?</condition>
<condition type="request-uri" operator="equal" next="or">/settings/[A-Za-z-_0-9]+</condition>
<condition type="request-uri" operator="equal" next="or">/user/[A-Za-z-_0-9]+/(homez|gallery/[0-9]+/[0-9]+|favorites/[0-9]+/[0-9]+)</condition>
<condition type="request-uri" operator="equal" next="or">/post/[0-9]+</condition>
<from>^.*$</from>
<to last="true">/</to>
</rule>
这些规则并不像我想要的那么通用,但它们是功能性的(我偷偷地怀疑这五个条件菊花链在一起有点性能影响)。这些规则几乎是专门为我的需求量身定制的,但希望它们至少可以成为大约 4 天前站在我的立场上的其他人的起点。
另一个需要注意的重要事项是,在您的 Angular 配置中(如果您使用的是 HTML5 模式 - 我不认为 hashbang 模式需要以下内容),请确保将requiredBase
设置为true
,例如:
$locationProvider.html5Mode({
enabled: true,
requireBase: true
});
并包括一个
<base href="/">
在 index.html 文件的<head>
中。如果你不这样做,Angular 会感到困惑,你的应用程序的某些部分可能无法正确加载 - 例如,我的 URI 的一部分正在被修剪。
另外,对于任何刚开始使用.htaccess/UrlRewriteFilter的人来说,请自己找Postman来测试你的规则 - 对于大多数人来说,这可能是一个主要的"嗯,duh",但对于我们其他人来说,这将是一个救命稻草:)
如果有人有任何关于如何提高效率/组合正则表达式的提示,请告诉我。