URL 管理
说明 Hugo 如何推导 URL,并用 slug、url、别名与永久链接定制地址。
概述
默认情况下,Hugo 渲染页面时生成的 URL 与文件在 content 目录中的路径一致。例如:
content/posts/post-1.md -> https://example.org/posts/post-1/通过 front matter 取值与项目配置,可以改变 URL 的结构与外观。
前置元数据
用以下 front matter 字段覆盖页面的默认 URL。
slug
在 front matter 中设置 slug 可以覆盖路径的最后一段。该字段不适用于 home 页面。
+++
title = "我的第一篇文章"
slug = "my-first-post"
+++最终 URL 为:
https://example.org/posts/my-first-post/自 v0.167.0 起,在 section、分类法或术语页面上设置 slug 时,Hugo 会把它应用到其下所有页面的 URL,包括页面的页面资源。例如:
+++
title = "Products"
slug = "shop"
+++最终 URL 为:
content/products/_index.md -> https://example.org/shop/
content/products/electronics/_index.md -> https://example.org/shop/electronics/
content/products/electronics/tv.md -> https://example.org/shop/electronics/tv/匹配到的永久链接模式优先于从祖先页面继承的 slug。
url
在 front matter 中设置 url 可以覆盖整条路径。该字段同样不适用于 home 页面。
与 slug 不同,section、分类法或术语页面上的 url 不会影响其下页面的 URL。
如果 slug 与 url 同时设置,url 的取值优先。
包含冒号
如果需要让 url 字段包含冒号,请用反斜杠转义:字符串用单引号包裹时写一个反斜杠,用双引号包裹时写两个反斜杠。使用 YAML front matter 且不加引号时,写一个反斜杠即可。
---
title: Example
url: "my\\:example"
---最终 URL 为 https://example.org/my:example/。如前所述,由于冒号(:)是保留字符,这种写法在 Windows 上会失败。
文件扩展名
以下 front matter:
+++
title = "我的第一篇文章"
url = "articles/my-first-article"
+++生成的 URL 是 https://example.org/articles/my-first-article/。若写成带扩展名的形式:
+++
title = "我的第一篇文章"
url = "articles/my-first-article.html"
+++生成的 URL 就是 https://example.org/articles/my-first-article.html。
开头的斜杠
在单语言项目中,url 无论是否带前导斜杠,都相对于 baseURL;在多语言项目中,带前导斜杠的 url 相对于 baseURL,不带前导斜杠的 url 相对于 baseURL 加上语言前缀。
| 站点类型 | front matter 中的 url |
生成的 URL |
|---|---|---|
| 单语言 | /about |
https://example.org/about/ |
| 单语言 | about |
https://example.org/about/ |
| 多语言 | /about |
https://example.org/about/ |
| 多语言 | about |
https://example.org/de/about/ |
令牌
url 取值中也可以使用令牌(token),常见于 cascade 区段:
+++
title = "Bar"
[[cascade]]
url = "/:sections[last]/:slug"
+++项目配置
永久链接、URL 外观与后处理都在项目配置中进行。
永久链接
用 permalinks 配置为页面定义自定义 URL 模式,Hugo 支持两种形式:按 section 的映射形式,以及支持页面匹配器(page matcher)的数组形式。页面匹配器可以按逻辑路径、页面类型、构建环境或站点来筛选页面。
映射形式以页面类型为键,为每个顶级 section 定义 URL 模式:
[permalinks.page]
articles = "/blog/:year/:month/:slug/"
[permalinks.section]
articles = "/blog/"要按语言配置永久链接,把 permalinks 键嵌在语言键之下:
[languages.de]
label = "Deutsch"
locale = "de-DE"
weight = 1
[languages.de.permalinks.page]
articles = "/artikel/:year/:month/:slug/"
[languages.de.permalinks.section]
articles = "/artikel/"数组形式用于把不同的 URL 模式应用到不同的页面子集。每个条目必须包含 pattern 键,Hugo 采用第一个匹配到的模式;可选的 target 键接受一个页面匹配器,省略 target 时该模式应用到所有页面。把不带 target 的模式放在末尾,即可作为兜底规则:
[[permalinks]]
pattern = "/:section/:slug/"令牌
在 URL 模式中可以使用以下令牌:
| 令牌 | 含义 |
|---|---|
:year、:month、:day |
front matter 中 date 字段的四位年份、两位月份、两位日期 |
:monthname、:weekdayname |
date 对应的月份名称、星期名称 |
:weekday、:yearday |
date 对应的星期序号(周日为 0)、一年中的第几天 |
:section、:sections |
内容的 section、section 层级 |
:sectionslug、:sectionslugs |
使用 slug 化名称的 section、section 层级(自 v0.149.0 起) |
:title |
front matter 中的 title,否则使用自动生成的标题 |
:slug |
front matter 中的 slug,否则依次退回 title、自动标题 |
:contentbasename |
内容文件的基本名(自 v0.144.0 起) |
:slugorcontentbasename |
front matter 中的 slug,否则使用内容文件的基本名 |
:sections 与 :sectionslugs 支持切片语法,例如 :sections[1:] 表示除第一段之外的全部,:sections[:last] 表示除最后一段之外的全部,:sections[last] 表示只取最后一段,:sections[1:2] 表示第 2 与第 3 段;:sectionslugs 的切片写法与此相同,例如 :sectionslugs[1:]、:sectionslugs[:last]、:sectionslugs[last]、:sectionslugs[1:2]。切片越界不会报错,因此索引不必精确。
:sectionslugs 使用 slug 化后的 section 名称:取名规则依次为 front matter 中的 slug、front matter 中的 title,最后是自动生成的标题。:sectionslug 同理,只是只包含当前这一个 section。
:filename、:slugorfilename 已废弃,请改用 :contentbasename 与 :slugorcontentbasename。时间相关的取值也可以使用 Go time 包中的布局字符串组件。
外观
用 uglyURLs 控制是否生成「丑陋 URL」(ugly URL)。Hugo 默认生成漂亮 URL(pretty URL),形如:
https://example.org/section/article/丑陋 URL 则把页面输出为带 .html 扩展名的文件:
https://example.org/section/article.html为全站开启:
uglyURLs = true也可以只对特定 section 开启:
[uglyURLs]
books = true
films = false后处理
Hugo 提供两个互斥的配置项,用于在页面渲染之后改写 URL。
规范 URL
开启后,Hugo 会在页面渲染完成后执行查找替换:查找带有 action、href、src、srcset、url 属性的站内相对 URL(以斜杠开头),为它们加上 baseURL 前缀,转换为绝对 URL。
<a href="/about"> -> <a href="https://example.org/about/">
<img src="/a.gif"> -> <img src="https://example.org/a.gif">canonifyURLs = true这是一种不完美的暴力替换方式,既可能影响正文内容,也可能影响 HTML 属性。
相对 URL
开启后,Hugo 同样在渲染后执行查找替换,把上述属性中的站内相对 URL 转换为相对于当前页面的地址。例如渲染 content/posts/post-1 时:
<a href="/about"> -> <a href="../../about">
<img src="/a.gif"> -> <img src="../../a.gif">relativeURLs = true别名
别名(alias)可以把旧 URL 重定向到新 URL,在重命名或移动内容时避免出现死链,保证已有的书签与外部链接继续可用。
定义别名
在 front matter 的 aliases 字段中列出旧路径,Hugo 会在构建时把它们解析为服务器相对路径,并计入 baseURL 与语言等内容维度前缀:
+++
title = "示例一"
date = 2025-02-02
aliases = ["/old-url", "old-name", "../old/path"]
+++如上所示,既可以写站内相对路径,也可以写页面相对路径,页面相对路径还允许使用目录跳转。以文件 content/examples/example-1.en.md 为参照,各种写法的解析结果如下:
| 路径类型 | 别名 | 服务器相对路径 |
|---|---|---|
| 站内相对 | /old-url |
/en/old-url/ |
| 页面相对 | old-name |
/en/examples/old-name/ |
| 页面相对 | ../old/path |
/en/old/path/ |
重定向方式
按托管环境与偏好,实现别名重定向有两种方式:客户端重定向与服务器端重定向。
客户端重定向
默认情况下 Hugo 使用客户端重定向,为每个别名生成一个小型 HTML 文件,其中包含 meta http-equiv="refresh" 标签,指示浏览器跳转到新地址。这种方式在所有托管服务上都可移植。
采用该方式时,Hugo 会在每个别名位置创建实体目录与 index.html。例如 content/posts/new.md 的页面相对别名为 old-path 时,会生成文件 public/posts/old-path/index.html。
除非你提供了自定义布局,Hugo 会使用内建的别名模板生成重定向文件,其内容为:
<!DOCTYPE html>
<html lang="{{ site.Language.Locale }}">
<head>
<title>{{ .Permalink }}</title>
{{ with .OutputFormats.Canonical }}<link rel="{{ .Rel }}" href="{{ .Permalink }}">{{ end }}
<meta charset="utf-8">
<meta http-equiv="refresh" content="0; url={{ .Permalink }}">
</head>
</html>要覆盖它,可在 layouts 目录中创建名为 alias.html 的文件,该模板可以访问以下上下文:
Permalink- (
string)目标页面的绝对 URL。 Page- (
page.Page)目标页面的完整Page对象。
服务器端重定向
另一种做法是在 Page 对象上使用 Aliases 方法,生成一份由 Web 服务器处理的配置文件。这种方式更高效:重定向在 HTTP 头层级完成,无需先让浏览器下载并解析 HTML 正文;同时 Hugo 也不必为每个别名写出实体目录与 HTML 文件,构建与部署都更快。
常见做法是编写一个模板,为具体的托管服务或服务器生成规则文件,例如 Cloudflare、GitLab Pages、Netlify 使用的 _redirects 文件,或 Apache、LiteSpeed 使用的 .htaccess 文件。
如果采用服务器端重定向,应把项目配置中的 disableAliases 设为 true,以停止生成单独的 HTML 文件。该设置只阻止实体 HTML 文件的生成,Page 对象上的 Aliases 方法在配置模板中依然可用。
baseURL
baseURL 是站点根地址,.Permalink、.RelPermalink 以及 absURL、relURL 等模板函数都受它影响。构建时可用 hugo --baseURL 临时覆盖,便于在预览、测试与生产环境之间切换。配置文件的组织方式见 配置。
排查地址问题
URL 在部分服务器、CDN 与对象存储上区分大小写,文件名里出现大写字母、空格或非 ASCII 字符时容易产生难以预期的链接。建议文件名统一使用小写字母、数字与连字符,并用 slug 把文件名与对外地址解耦。
# 构建时提示重复的目标路径
hugo --printPathWarnings
# 查看最终生效的配置
hugo config出现地址不符预期时,先用 hugo config 确认最终生效的 baseURL、permalinks、uglyURLs 取值,再用 --printPathWarnings 检查是否有多个页面写出同一个文件。