本参考文档解释了 Discourse 永久链接如何将旧 URL 路径重定向到新目的地、永久链接规范化(normalizations)的工作原理,以及如何在迁移或 URL 结构更改后测试和排查重定向问题。
所需用户级别:管理员
仅在使用导入器、脚本或 Rails 控制台创建永久链接时需要控制台访问权限
当你从其他论坛迁移或更改站点的 URL 结构时,来自搜索引擎、书签、电子邮件或其他网站的旧链接可能不再指向正确的页面。
永久链接允许你使用 301 Moved Permanently(永久移动)重定向将旧 URL 路径重定向到其新目的地。
永久链接是精确的路径映射。例如,如果以下旧 URL 不再有效:
https://discourse.example.com/forum/topic/123
你可以创建一个永久链接,使其重定向到新主题:
https://discourse.example.com/t/welcome-to-our-community/456
什么是永久链接
永久链接是从一个旧 URL 路径到一个新目的地的精确映射。
例如:
forum/topic/123 → /t/welcome-to-our-community/456
在以下情况下,永久链接非常有用:
- 你从其他论坛平台迁移
- 旧链接已被搜索引擎索引
- 旧链接被用于电子邮件、文档或其他网站
- 你更改了站点 URL 的结构
- 你希望旧路径重定向到主题、帖子、分类、标签、用户或外部 URL
每个永久链接 URL 映射到一个目的地。
永久链接是精确匹配。永久链接 URL 字段不支持通配符或正则表达式。如果许多旧 URL 遵循可预测的模式,请使用永久链接规范化在精确查找之前转换传入的 URL。
永久链接与规范化
永久链接和规范化执行不同的操作:
| 功能 | 作用 | 示例 |
|---|---|---|
| 永久链接 | 将一个保存的旧路径重定向到一个目的地 | old/topic/123 → Topic 456 |
| 规范化 | 在永久链接查找之前更改传入的路径 | old/topic/123-title → old/topic/123 |
规范化本身不会执行重定向。它仅更改用于查找已保存永久链接的路径。
规范化应用后,你仍然需要匹配的永久链接。
快速示例
重定向旧主题 URL
旧 URL:
https://discourse.example.com/forum/topic/123
永久链接 URL:
forum/topic/123
目的地类型:
Topic
目的地:
456
结果:
/forum/topic/123 → /t/welcome-to-our-community/456
重定向带有查询字符串的旧 URL
旧 URL:
https://discourse.example.com/viewtopic.php?t=123
永久链接 URL:
viewtopic.php?t=123
目的地类型:
Topic
目的地:
456
结果:
/viewtopic.php?t=123 → /t/welcome-to-our-community/456
重定向具有相同模式的许多旧 URL
旧 URL:
/forum/support/123-how-do-i-reset-my-password.html
/forum/general/456-how-do-i-change-my-email.html
你可以使用规范化在查找之前简化它们:
/forum/support/123-how-do-i-reset-my-password.html → forum/123
/forum/general/456-how-do-i-change-my-email.html → forum/456
然后创建精确的永久链接:
forum/123 → Topic 1001
forum/456 → Topic 1002
作为永久链接 URL 输入什么
输入旧路径,而不是完整 URL。
例如,使用:
forum/topic/123
或:
/forum/topic/123
不要使用完整的旧 URL:
https://discourse.example.com/forum/topic/123
接受前导斜杠,但在保存永久链接时会将其移除。以下两个条目是等效的:
/forum/topic/123
forum/topic/123
两者都存储为:
forum/topic/123
保存永久链接时会移除前导和尾随空格。
查询字符串是匹配的一部分
永久链接匹配完整的请求路径,包括查询字符串。
这意味着以下两个 URL 是不同的永久链接匹配项:
/old/topic/123
/old/topic/123?utm_source=example
如果旧 URL 包含查询字符串,则:
- 创建一个包含查询字符串的永久链接,或
- 使用永久链接规范化在匹配之前移除或简化查询字符串
对于大多数分析或跟踪参数,使用规范化通常比创建许多单独的永久链接更好。
例如,以下保存的永久链接:
docs/123
不一定匹配以下请求的 URL:
/docs/123?utm_source=newsletter
除非规范化在查找之前移除了查询字符串。
从分析工具、搜索控制台报告、浏览器或电子邮件活动中复制旧 URL 时,请检查是否添加了跟踪参数。
URL 片段不是匹配的一部分
URL 片段不会发送到服务器。
例如,以下 URL:
/old/topic#post-12
到达服务器时显示为:
/old/topic
永久链接或规范化无法匹配:
#post-12
除非 # 在实际请求中被编码为 %23。
支持的永久链接目的地
永久链接可以重定向到以下目的地类型之一:
- 主题 (Topic)
- 帖子 (Post)
- 分类 (Category)
- 标签 (Tag)
- 用户 (User)
- 外部或相对 URL
外部或相对 URL 目的地可用于此类重定向:
old/privacy-policy → https://archive.discourse.example.com/privacy
或:
old/preferences → /my/preferences
谨慎使用外部 URL 目的地。它们会将访问者重定向到你的站点之外,并且不检查目标 URL 是否存在。
重定向到迁移后的主题、帖子、分类、标签或用户时,请优先使用内部目的地类型。当目标页面不由内部对象表示时,使用外部 URL 目的地。
手动添加永久链接
要手动添加永久链接:
- 前往
/admin/config/permalinks。 - 选择 永久链接 (Permalinks) 选项卡。
- 点击 添加永久链接 (Add permalink)。
- 在 URL 字段中输入旧路径。
- 选择 永久链接类型 (Permalink type)。
- 输入或选择目的地。
- 保存永久链接。
- 在浏览器中使用
curl测试旧 URL。
示例:
URL:
forum/topic/123
永久链接类型:
Topic
目的地:
456
对以下 URL 的请求:
https://discourse.example.com/forum/topic/123
将重定向到主题 456。
目的地值
目的地值取决于永久链接类型。
| 永久链接类型 | 目的地 |
|---|---|
| 主题 (Topic) | 一个主题 |
| 帖子 (Post) | 一个帖子 |
| 分类 (Category) | 一个分类 |
| 标签 (Tag) | 一个标签 |
| 用户 (User) | 一个用户 |
| 外部或相对 URL | 完整的外部 URL 或相对路径 |
示例:
forum/topic/123 → Topic 456
forum/post/789 → Post 789
forum/category/support → Category support
forum/tag/example → Tag example
forum/user/alice → User alice
old/privacy → https://archive.discourse.example.com/privacy
old/preferences → /my/preferences
在迁移期间创建永久链接
许多官方导入器会自动为迁移后的分类、主题、帖子或用户创建永久链接。
对于大型迁移,永久链接通常由导入器或迁移脚本创建,而不是逐个手动输入。
如果你正在编写自定义导入器,请为迁移后应继续工作的旧 URL 创建永久链接记录。
例如:
Permalink.create!(url: "discussion/12345", topic_id: 987)
在此示例中,discussion/12345 是旧路径,987 是 Discourse 主题 ID。
也接受前导斜杠:
Permalink.create!(url: "/discussion/12345", topic_id: 987)
两个示例都将永久链接 URL 存储为:
discussion/12345
要重定向到外部 URL:
Permalink.create!(
url: "discussion/12345",
external_url: "https://archive.discourse.example.com/discussion/12345"
)
在导入器中创建永久链接时:
- 存储旧路径,而不是完整的旧域名
- 仅当匹配需要时才包含查询字符串
- 确保每个旧路径映射到一个目的地
- 在插入记录之前检查重复项
- 记住永久链接 URL 必须是唯一的
如果你运行多次测试迁移,最终的主题和帖子 ID 在每次运行之间可能会发生变化。在生产迁移数据稳定时生成或验证最终的永久链接映射。
什么是永久链接规范化
永久链接规范化在查找匹配的永久链接之前更改传入的旧路径。
当许多旧 URL 遵循相同的可预测模式时,规范化非常有用。
例如,假设你的旧论坛使用如下 URL:
/forum/support/123-how-do-i-reset-my-password.html
但你保存的永久链接更简单:
forum/123
规范化可以将传入的请求转换为保存的永久链接路径:
/forum/support/123-how-do-i-reset-my-password.html
↓
forum/123
然后永久链接可以重定向:
forum/123 → /t/how-do-i-reset-my-password/456
规范化本身不会执行重定向。它仅更改用于永久链接查找的路径。
你仍然需要规范化路径的匹配永久链接。
大多数站点不需要永久链接规范化。仅当许多旧 URL 遵循可预测的模式,且为每个旧 URL 创建一个永久链接不切实际时才使用它们。
永久链接和规范化如何协同工作
当请求旧 URL 时,流程如下:
访客请求旧 URL
↓
应用永久链接规范化(如果已配置)
↓
使用 resulting 路径执行永久链接查找
↓
如果存在匹配的永久链接,访客将被重定向
例如:
请求的 URL:
/old/topic/123?utm_source=newsletter
规范化将其更改为:
old/topic/123
永久链接将其重定向到:
/t/new-topic-title/456
添加永久链接规范化
永久链接规范化是从永久链接设置中配置的。
要添加一个:
- 前往
/admin/config/permalinks。 - 选择 设置 (Settings) 选项卡。
- 将规则添加到
permalink normalizations设置。 - 保存设置。
- 测试应被规范化的旧 URL。
- 确认规范化后的路径匹配现有的永久链接。
语法为:
/<regex>/<replacement>
多个规则用 | 分隔。
例如:
/old\/topic\/(\d+).*/topic/\1
这可以将:
old/topic/123-my-old-title
转换为:
topic/123
替换部分使用 Ruby 替换语法,因此捕获组写为:
\1
\2
\3
重要的规范化规则
保持规范化规则简单。
- 规范化使用 Ruby 正则表达式。
- 正则表达式部分中的字面
/字符必须转义为\/。 - 替换部分中的字面
/字符不需要转义。 - 多个规范化规则用
|分隔。 - 因为
|用于分隔规则,所以避免使用带有|的正则表达式交替。 - 每个规则使用单个替换,而不是全局替换。
- 规则按顺序应用。
- 匹配的规则按顺序应用。
- 规范化在永久链接查找之前应用。
- 规范化在保存永久链接记录时也应用。
- 设置验证器会捕获无效的正则表达式,但可能无法捕获每个行为与预期不同的规则。
警告: 在保存永久链接记录时会应用规范化。如果在管理界面中输入未规范化的 URL,它可能会被存储为规范化后的结果。如果在创建永久链接后添加或更改规范化,请仔细测试并检查新保存的永久链接 URL 是如何存储的。
规范化示例
重定向带有额外标题文本的旧 URL
旧 URL:
/forum/support/123-how-do-i-reset-my-password.html
/forum/general/456-how-do-i-change-my-email.html
你可以将它们规范化为更简单的永久链接路径:
forum/123
forum/456
示例规范化:
/forum\/[^\/]+\/(\d+).*/forum/\1
然后创建永久链接:
forum/123 → Topic 1001
forum/456 → Topic 1002
忽略跟踪查询字符串
旧请求 URL:
/docs/123?utm_source=newsletter
保存的永久链接:
docs/123
规范化:
/(docs\/\d+)\?.*/\1
这将在永久链接查找之前移除查询字符串。
保留重要的查询参数
一些旧论坛使用查询参数作为稳定的主题标识符。
例如:
viewtopic.php?f=10&t=123
viewtopic.php?t=123
你可能希望将它们规范化为:
viewtopic.php?t=123
示例规范化:
/(viewtopic\.php\?)(?:.*&)?(t=\d+).*/\1\2
然后创建永久链接:
viewtopic.php?t=123 → Topic 456
正则表达式和通配符重定向
永久链接 URL 字段不支持正则表达式或通配符。
以下作为永久链接 URL 将不起作用:
forum/topic/*
以下作为永久链接 URL 也不起作用:
forum/topic/(\d+)
如果你需要基于模式的处理,请使用永久链接规范化将传入的 URL 重写为可以匹配精确保存的永久链接的形式。
例如:
/forum/topic/123-title → forum/topic/123
然后创建正常的精确永久链接:
forum/topic/123 → Topic 456
路由优先级和内置路径
永久链接路由在常规应用路由之后进行检查。
这意味着有效的现有路由可能在检查永久链接之前正常解析。
小心以内置路径开头的旧 URL,例如:
/t
/c
/u
/tag
/tags
例如,以下旧论坛 URL 可能看起来像内置的分类路由:
/c/blog/old-platform-url/ba-p/12345
如果旧 URL 与有效的现有路由冲突,有效路由可能优先于永久链接。
同样,如果你为看起来像现有主题路由的路径创建永久链接,例如:
t/123
常规主题路由可能在永久链接查找之前被处理。
一些内置的未找到路由具有额外的回退行为,但你不应该依赖于此。始终测试与内置路径重叠的旧 URL。
如果你需要旧主题 URL 重定向到其他地方,旧主题通常必须不再解析为有效的主题路由。
权限和私有内容
指向内部目的地的永久链接遵循正常的权限设置。
如果永久链接指向私有或受限的主题、帖子、分类、标签或用户,无法访问该目的地的访客将获得 404 错误,而不是重定向。
指向外部 URL 的永久链接不检查内部内容权限。
特殊字符和编码 URL
仔细测试带有特殊字符的 URL。
这包括带有以下内容的 URL:
- 空格
+%&':- 括号
- 非拉丁字符
永久链接匹配使用移除前导斜杠并应用配置的规范化后的编码请求路径。编码差异可能导致 URL 无法匹配你期望的永久链接。
例如,以下 URL 可能不等效,具体取决于旧 URL 的请求和存储方式:
old/topic/hello%20world
old/topic/hello+world
在 URL 示例中使用 %20 表示空格。在 URL 路径中,+ 不等于空格。
字符如 &、? 和 # 在 URL 中具有特殊含义。如果它们应作为字面路径字符,则应进行百分号编码。
如有疑问,请测试用户或搜索引擎将请求的确切旧 URL。
限制
永久链接旨在将旧路径重定向到新目的地。它们不是通用重定向或重写引擎。
重要限制:
- 永久链接 URL 存储为路径和查询字符串,而不是完整 URL。
- 完整 URL 不会自动转换为路径。
- 规范化后,永久链接 URL 必须是唯一的。
- 永久链接 URL 只能有一个目的地。
- 支持的目的地仅限于主题、帖子、分类、标签、用户以及外部或相对 URL。
- 永久链接使用
301 Moved Permanently;没有每个永久链接使用302的选项。 - 永久链接 URL 字段不支持通配符或正则表达式。
- 查询字符串是查找键的一部分。
- URL 片段(如
#post-12)不会发送到服务器,也无法匹配。 - 匹配不使用请求方案或主机。
- 原生路由在捕获所有永久链接路由之前进行检查。
- 内部目的地会进行权限检查。
- 外部 URL 目的地绕过内部内容权限检查。
- 永久链接规范化使用 Ruby 正则表达式。
- 规范化规则用
|分隔,因此避免将|用作正则表达式交替。 - 规范化规则每个规则使用单个替换,而不是全局替换。
- 规范化在查找之前和保存永久链接记录之前均应用。
- 设置验证器会捕获无效的正则表达式,但可能无法捕获每个行为与预期不同的规则。
对于大多数站点,简单的单对单永久链接比复杂的规范化规则更容易维护。仅当旧 URL 遵循可预测的模式时才使用规范化。
避免将所有旧 URL 重定向到主页
不要将所有旧 URL 重定向到你的主页。
将每个旧 URL 重定向到最相关的新页面。如果没有等效内容,404 可能比将用户和搜索引擎发送到不相关的页面更好。
良好的重定向是具体的:
old/topic/123 → 关于同一主题的新主题
糟糕的重定向是通用的:
old/topic/123 → 主页
old/topic/456 → 主页
old/topic/789 → 主页
测试你的重定向
创建永久链接或规范化后,测试一些旧 URL 的样本。
你可以在浏览器中测试,或使用:
curl -I https://discourse.example.com/forum/topic/123
工作的永久链接重定向应返回类似以下的永久重定向:
HTTP/2 301
location: https://discourse.example.com/t/welcome-to-our-community/456
测试每个旧 URL 模式的示例,包括:
- 旧主题 URL
- 旧分类 URL
- 旧帖子 URL
- 带有查询字符串的 URL
- 带有特殊字符的 URL
- 来自搜索结果的 URL
- 来自旧电子邮件或文档的 URL
- 以
/t、/c或/u等内置路径开头的 URL - 外部 URL 重定向
故障排除
如果旧 URL 没有重定向,请检查以下常见原因:
- 确认永久链接存在。
- 确认永久链接 URL 是旧路径,而不是完整的旧域名。
- 检查旧 URL 是否包含查询字符串。
- 如果使用规范化,确认规范化后的路径匹配保存的永久链接。
- 检查是否有内置路由优先。
- 检查目的地是否私有或受限。
- 检查编码差异,例如
%20与+。 - 检查永久链接保存时规范化是否更改了 URL。
- 确认内容已迁移。
- 使用浏览器或
curl -I测试确切的旧 URL。
最常见的问题是:
- 输入了完整的旧 URL 而不是旧路径
- 缺少或意外的查询字符串
- 期望通配符或正则表达式在永久链接 URL 字段中起作用
- 旧 URL 与内置路径重叠
- 私有或受限的目的地
- 编码差异
- 规范化意外更改了路径