URL 管理
在 Hugo 中,URL 管理是一个灵活且强大的方面,它允许您通过前置元数据(front matter)和站点配置(site configuration)来控制网站链接的结构和外观。
默认 URL 行为
基本规则
默认情况下,当 Hugo 渲染页面时,生成的 URL 会匹配内容目录中的文件路径。
例如:
- 文件路径:
content/posts/my-first-post.md
- 默认 URL:
/posts/my-first-post/
文件系统映射
content/
├── _index.md → /
├── about.md → /about/
├── contact.md → /contact/
├── posts/
│ ├── _index.md → /posts/
│ ├── post-1.md → /posts/post-1/
│ └── post-2.md → /posts/post-2/
└── docs/
├── _index.md → /docs/
└── getting-started.md → /docs/getting-started/
前置元数据 URL 控制
前置元数据中的 slug
和 url
字段对 URL 管理最为重要。
slug 字段
slug
用于覆盖 URL 路径的最后一个片段:
---
title: "My First Post"
slug: "my-first-post"
---
使用示例
# content/posts/article-with-long-name.md
---
title: "一篇关于 Hugo 静态网站生成器的详细介绍文章"
slug: "hugo-intro"
---
结果:
- 默认 URL:
/posts/article-with-long-name/
- 使用 slug:
/posts/hugo-intro/
url 字段
url
用于覆盖整个 URL 路径:
---
title: "About Us"
url: "/company/about/"
---
重要特性
- 适用于常规页面和章节页面
- Hugo 不会净化
url
字段,需要小心使用 url
优先于slug
使用示例
# content/posts/special-announcement.md
---
title: "重要公告"
url: "/announcement/2025/important-news/"
---
# content/docs/api-reference.md
---
title: "API 参考"
url: "/developers/api/"
---
多语言 URL 处理
在多语言站点中,url
值的处理方式:
# content/zh/about.md
---
title: "关于我们"
url: "/guanyu/" # 不带前导斜杠:相对于 baseURL + 语言前缀
---
# content/en/about.md
---
title: "About Us"
url: "/about/" # 带前导斜杠:相对于 baseURL
---
站点配置 URL 管理
permalinks 配置
在站点配置中为不同页面类型定义 URL 模式:
# hugo.toml
[permalinks]
posts = "/blog/:year/:month/:title/"
docs = "/documentation/:section/:title/"
news = "/news/:year/:slug/"
可用占位符
:year
:年份(2025):month
:月份(01-12):monthname
:月份名称(January):day
:日期(01-31):weekday
:星期(Monday):weekdayname
:星期名称(Monday):yearday
:年中的天数(001-366):section
:内容章节:sections
:所有章节的层次结构:title
:页面标题(URL 化):slug
:页面 slug:filename
:文件名(不含扩展名)
使用示例
[permalinks]
# 博客文章:/blog/2025/01/my-post-title/
posts = "/blog/:year/:month/:title/"
# 文档:/docs/getting-started/installation/
docs = "/docs/:section/:title/"
# 新闻:/news/2025/important-announcement/
news = "/news/:year/:slug/"
# 项目:/projects/my-awesome-project/
projects = "/projects/:slug/"
语言特定永久链接
[languages.zh]
[languages.zh.permalinks]
posts = "/wenzhang/:year/:month/:title/"
docs = "/wendang/:section/:title/"
[languages.en]
[languages.en.permalinks]
posts = "/posts/:year/:month/:title/"
docs = "/docs/:section/:title/"
uglyURLs 配置
控制 URL 的美观程度:
# hugo.toml
uglyURLs = false # 默认:漂亮 URL (/posts/my-post/)
# uglyURLs = true # 丑陋 URL (/posts/my-post.html)
针对特定章节配置
[uglyURLs]
posts = true # /posts/my-post.html
docs = false # /docs/guide/
baseURL 配置
站点的绝对 URL 基础:
baseURL = 'https://example.com/'
# 多环境配置
[environments.production]
baseURL = 'https://example.com/'
[environments.staging]
baseURL = 'https://staging.example.com/'
[environments.development]
baseURL = 'http://localhost:1313/'
别名和重定向
aliases 字段
通过 aliases
创建旧 URL 的重定向:
---
title: "新页面标题"
url: "/new-path/"
aliases:
- "/old-path/"
- "/another-old-path/"
- "/legacy/old-page.html"
---
自动生成重定向
Hugo 会为每个别名生成客户端重定向文件:
<!-- public/old-path/index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Redirecting...</title>
<link rel="canonical" href="/new-path/">
<meta name="robots" content="noindex">
<meta charset="utf-8">
<meta http-equiv="refresh" content="0; url=/new-path/">
</head>
<body>
<h1>Redirecting...</h1>
<a href="/new-path/">Click here if you are not redirected</a>
</body>
</html>
批量重定向
# content/posts/renamed-article.md
---
title: "重命名的文章"
date: 2025-06-19
aliases:
- "/blog/old-article-name/"
- "/posts/2024/12/old-article-name/"
- "/articles/old-article-name.html"
---
高级 URL 管理
条件 URL 生成
# 使用占位符的动态 URL
---
title: "{{ .Title }}"
url: "/{{ .Section }}/{{ .Date.Format \"2006\" }}/{{ .Params.category | urlize }}/"
---
自定义 URL 模式
# hugo.toml
[permalinks]
# 复杂的 URL 模式
posts = "/:sections[1:]/:year/:month/:day/:slug/"
# 条件模式(通过 cascade 实现)
tutorials = "/learn/:title/"
guides = "/guides/:section/:title/"
动态重定向配置
# hugo.toml
[mediaTypes]
[mediaTypes."text/netlify"]
suffixes = [""]
[outputFormats]
[outputFormats.redirects]
mediaType = "text/netlify"
baseName = "_redirects"
isPlainText = true
notAlternative = true
[outputs]
home = ["HTML", "redirects"]
<!-- layouts/index.redirects -->
{{ range .Site.AllPages -}}
{{ range .Aliases -}}
{{ . }} {{ $.Permalink }} 301
{{ end -}}
{{ end -}}
模板中的 URL 处理
基本 URL 方法
<!-- 绝对 URL -->
{{ .Permalink }}
<!-- https://example.com/posts/my-post/ -->
<!-- 相对 URL -->
{{ .RelPermalink }}
<!-- /posts/my-post/ -->
<!-- 基础 URL -->
{{ .Site.BaseURL }}
<!-- https://example.com/ -->
URL 构建函数
<!-- 构建相对 URL -->
{{ relURL "/css/style.css" }}
<!-- /css/style.css -->
<!-- 构建绝对 URL -->
{{ absURL "/css/style.css" }}
<!-- https://example.com/css/style.css -->
<!-- URL 参数编码 -->
{{ urlquery "hello world" }}
<!-- hello+world -->
引用其他页面
<!-- 使用 ref 短代码 -->
{{ ref . "posts/my-other-post.md" }}
<!-- 使用 relref 短代码 -->
{{ relref . "docs/getting-started.md" }}
<!-- 在模板中使用 -->
{{ with .Site.GetPage "/posts/featured-post" }}
<a href="{{ .Permalink }}">{{ .Title }}</a>
{{ end }}
条件链接生成
<!-- 检查页面存在性 -->
{{ $page := .Site.GetPage "/about" }}
{{ if $page }}
<a href="{{ $page.Permalink }}">{{ $page.Title }}</a>
{{ else }}
<span>About page not found</span>
{{ end }}
<!-- 多语言链接 -->
{{ range .Site.Languages }}
{{ if eq . $.Site.Language }}
<span class="current">{{ .LanguageName }}</span>
{{ else }}
{{ with $.Translations.Get .Lang }}
<a href="{{ .Permalink }}">{{ .Language.LanguageName }}</a>
{{ end }}
{{ end }}
{{ end }}
SEO 优化
规范链接
<!-- 设置规范 URL -->
<link rel="canonical" href="{{ .Permalink }}">
<!-- 多语言规范链接 -->
{{ range .Translations }}
<link rel="alternate" hreflang="{{ .Lang }}" href="{{ .Permalink }}">
{{ end }}
<link rel="alternate" hreflang="x-default" href="{{ .Site.BaseURL }}">
Open Graph URL
<meta property="og:url" content="{{ .Permalink }}">
<meta property="og:type" content="article">
<meta property="og:title" content="{{ .Title }}">
结构化数据
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"url": "{{ .Permalink }}",
"headline": "{{ .Title }}",
"datePublished": "{{ .Date.Format "2006-01-02T15:04:05Z07:00" }}",
"author": {
"@type": "Person",
"name": "{{ .Params.author }}"
}
}
</script>
调试和验证
检查 URL 生成
# 显示所有页面的 URL
hugo list all | grep -E "(permalink|path)"
# 检查特定页面的 URL
hugo list all | grep "my-post"
验证重定向
# 检查生成的重定向文件
find public -name "index.html" -path "*/old-path/*"
# 测试重定向
curl -I http://localhost:1313/old-path/
URL 调试模板
<!-- 在开发环境显示 URL 调试信息 -->
{{ if not hugo.IsProduction }}
<div style="background: #f0f0f0; padding: 10px; margin: 10px 0;">
<h4>URL Debug Info</h4>
<p><strong>Permalink:</strong> {{ .Permalink }}</p>
<p><strong>RelPermalink:</strong> {{ .RelPermalink }}</p>
<p><strong>Kind:</strong> {{ .Kind }}</p>
<p><strong>Section:</strong> {{ .Section }}</p>
<p><strong>Type:</strong> {{ .Type }}</p>
{{ with .Aliases }}
<p><strong>Aliases:</strong> {{ delimit . ", " }}</p>
{{ end }}
</div>
{{ end }}
最佳实践
1. URL 设计原则
- 保持简洁:避免过长的 URL
- 语义化:URL 应该反映内容结构
- 一致性:在整个站点保持 URL 模式一致
- 永久性:避免频繁更改 URL 结构
2. 重定向管理
# 规范的重定向配置
---
title: "新文章标题"
date: 2025-06-19
url: "/posts/new-article-title/"
aliases:
- "/blog/old-article-title/" # 旧博客路径
- "/2024/12/old-article/" # 旧日期路径
- "/articles/old-title.html" # 遗留 HTML 路径
---
3. 多语言 URL 策略
# 建议的多语言配置
[languages.zh]
[languages.zh.permalinks]
posts = "/wenzhang/:year/:month/:title/"
[languages.en]
[languages.en.permalinks]
posts = "/posts/:year/:month/:title/"
4. 性能考虑
- 避免过深的 URL 层次结构
- 使用静态 URL 而非动态生成
- 合理使用别名,避免过多重定向
5. 安全注意事项
# 避免特殊字符和保留字符
---
title: "安全的文章标题"
slug: "safe-article-title" # 而不是包含特殊字符的 slug
url: "/posts/safe-path/" # 避免 <、>、: 等字符
---
通过灵活的 URL 管理,您可以创建用户友好、SEO 优化且易于维护的网站链接结构。