URL 管理
概述
默认情况下,当 Hugo 渲染页面时,生成的 URL 与 content
目录中的文件路径匹配。 例如
content/posts/post-1.md → https://example.org/posts/post-1/
您可以使用前言值和站点配置选项来更改 URL 的结构和外观。
前言
slug
在前言中设置 slug
可以覆盖路径的最后一段。 slug
值不影响章节页面。
---
slug: my-first-post
title: My First Post
---
+++
slug = 'my-first-post'
title = 'My First Post'
+++
{
"slug": "my-first-post",
"title": "My First Post"
}
生成的 URL 将是
https://example.org/posts/my-first-post/
url
在前言中设置 url
可以覆盖整个路径。 将此用于常规页面或章节页面。
如果在前言中同时设置了 slug
和 url
,则 url
值优先。
包含冒号
v0.136.0 新增如果需要在 url
前言字段中包含冒号,请使用反斜杠字符对其进行转义。 如果将字符串括在单引号中,则使用一个反斜杠;如果将字符串括在双引号中,则使用两个反斜杠。 对于 YAML 前言,如果省略引号,则使用单个反斜杠。
例如,使用以下前言
---
title: Example
url: my\:example
---
+++
title = 'Example'
url = 'my\:example'
+++
{
"title": "Example",
"url": "my\\:example"
}
生成的 URL 将是
https://example.org/my:example/
如上所述,这在 Windows 上会失败,因为冒号 (:
) 是保留字符。
文件扩展名
使用以下前言
---
title: My First Article
url: articles/my-first-article
---
+++
title = 'My First Article'
url = 'articles/my-first-article'
+++
{
"title": "My First Article",
"url": "articles/my-first-article"
}
生成的 URL 将是
https://example.org/articles/my-first-article/
如果包含文件扩展名
---
title: My First Article
url: articles/my-first-article.html
---
+++
title = 'My First Article'
url = 'articles/my-first-article.html'
+++
{
"title": "My First Article",
"url": "articles/my-first-article.html"
}
生成的 URL 将是
https://example.org/articles/my-first-article.html
前导斜杠
对于单语言站点,带或不带前导斜杠的 url
值都相对于 baseURL
。 对于多语言站点,带有前导斜杠的 url
值相对于 baseURL
,而不带有前导斜杠的 url
值相对于 baseURL
加上语言前缀。
站点类型 | 前言 url |
生成的 URL |
---|---|---|
单语言 | /about |
https://example.org/about/ |
单语言 | about |
https://example.org/about/ |
多语言 | /about |
https://example.org/about/ |
多语言 | about |
https://example.org/de/about/ |
前言中的 Permalink 标记
v0.131.0 新增在设置 url
值时,您还可以使用标记。 这通常用于 cascade
部分
---
cascade:
- url: /:sections[last]/:slug
title: Bar
---
+++
title = 'Bar'
[[cascade]]
url = '/:sections[last]/:slug'
+++
{
"cascade": [
{
"url": "/:sections[last]/:slug"
}
],
"title": "Bar"
}
站点配置
永久链接
在您的站点配置中,为每个顶级部分定义一个 URL 模式。每个 URL 模式可以针对给定的语言和/或页面类型。
Front matter 中的 url
值会覆盖在站点配置的 permalinks
部分中定义的 URL 模式。
单语示例
使用以下内容结构
content/
├── posts/
│ ├── bash-in-slow-motion.md
│ └── tls-in-a-nutshell.md
├── tutorials/
│ ├── git-for-beginners.md
│ └── javascript-bundling-with-hugo.md
└── _index.md
在 “training” 下渲染教程,并在 “articles” 下使用基于日期的层次结构渲染帖子
permalinks:
page:
posts: /articles/:year/:month/:slug/
tutorials: /training/:slug/
section:
posts: /articles/
tutorials: /training/
[permalinks]
[permalinks.page]
posts = '/articles/:year/:month/:slug/'
tutorials = '/training/:slug/'
[permalinks.section]
posts = '/articles/'
tutorials = '/training/'
{
"permalinks": {
"page": {
"posts": "/articles/:year/:month/:slug/",
"tutorials": "/training/:slug/"
},
"section": {
"posts": "/articles/",
"tutorials": "/training/"
}
}
}
发布的站点结构将是
public/
├── articles/
│ ├── 2023/
│ │ ├── 04/
│ │ │ └── bash-in-slow-motion/
│ │ │ └── index.html
│ │ └── 06/
│ │ └── tls-in-a-nutshell/
│ │ └── index.html
│ └── index.html
├── training/
│ ├── git-for-beginners/
│ │ └── index.html
│ ├── javascript-bundling-with-hugo/
│ │ └── index.html
│ └── index.html
└── index.html
要为内容根目录中的常规页面创建基于日期的层次结构
permalinks:
page:
/: /:year/:month/:slug/
[permalinks]
[permalinks.page]
'/' = '/:year/:month/:slug/'
{
"permalinks": {
"page": {
"/": "/:year/:month/:slug/"
}
}
}
对分类术语使用相同的方法。例如,要省略 URL 的分类段
permalinks:
term:
tags: /:slug/
[permalinks]
[permalinks.term]
tags = '/:slug/'
{
"permalinks": {
"term": {
"tags": "/:slug/"
}
}
}
多语示例
使用 permalinks
配置作为本地化策略的一个组成部分。
使用以下内容结构
content/
├── en/
│ ├── books/
│ │ ├── les-miserables.md
│ │ └── the-hunchback-of-notre-dame.md
│ └── _index.md
└── es/
├── books/
│ ├── les-miserables.md
│ └── the-hunchback-of-notre-dame.md
└── _index.md
以及此站点配置
defaultContentLanguage: en
defaultContentLanguageInSubdir: true
languages:
en:
contentDir: content/en
languageCode: en-US
languageDirection: ltr
languageName: English
permalinks:
page:
books: /books/:slug/
section:
books: /books/
weight: 1
es:
contentDir: content/es
languageCode: es-ES
languageDirection: ltr
languageName: Español
permalinks:
page:
books: /libros/:slug/
section:
books: /libros/
weight: 2
defaultContentLanguage = 'en'
defaultContentLanguageInSubdir = true
[languages]
[languages.en]
contentDir = 'content/en'
languageCode = 'en-US'
languageDirection = 'ltr'
languageName = 'English'
weight = 1
[languages.en.permalinks]
[languages.en.permalinks.page]
books = '/books/:slug/'
[languages.en.permalinks.section]
books = '/books/'
[languages.es]
contentDir = 'content/es'
languageCode = 'es-ES'
languageDirection = 'ltr'
languageName = 'Español'
weight = 2
[languages.es.permalinks]
[languages.es.permalinks.page]
books = '/libros/:slug/'
[languages.es.permalinks.section]
books = '/libros/'
{
"defaultContentLanguage": "en",
"defaultContentLanguageInSubdir": true,
"languages": {
"en": {
"contentDir": "content/en",
"languageCode": "en-US",
"languageDirection": "ltr",
"languageName": "English",
"permalinks": {
"page": {
"books": "/books/:slug/"
},
"section": {
"books": "/books/"
}
},
"weight": 1
},
"es": {
"contentDir": "content/es",
"languageCode": "es-ES",
"languageDirection": "ltr",
"languageName": "Español",
"permalinks": {
"page": {
"books": "/libros/:slug/"
},
"section": {
"books": "/libros/"
}
},
"weight": 2
}
}
}
发布的站点结构将是
public/
├── en/
│ ├── books/
│ │ ├── les-miserables/
│ │ │ └── index.html
│ │ ├── the-hunchback-of-notre-dame/
│ │ │ └── index.html
│ │ └── index.html
│ └── index.html
├── es/
│ ├── libros/
│ │ ├── les-miserables/
│ │ │ └── index.html
│ │ ├── the-hunchback-of-notre-dame/
│ │ │ └── index.html
│ │ └── index.html
│ └── index.html
└── index.html
令牌
在定义 URL 模式时使用这些令牌。您还可以在设置 front matter 中的 url
值时使用这些令牌。
:year
- 在 front matter
date
字段中定义的 4 位数年份。 :month
- 在 front matter
date
字段中定义的 2 位数月份。 :monthname
- 在 front matter
date
字段中定义的月份名称。 :day
- 在 front matter
date
字段中定义的 2 位数日期。 :weekday
- 在 front matter
date
字段中定义的 1 位数星期几(星期日 = 0)。 :weekdayname
- 在 front matter
date
字段中定义的星期几名称。 :yearday
- 在 front matter
date
字段中定义的 1 到 3 位数年份中的第几天。 :section
- 内容的节。
:sections
- 内容的节层次结构。您可以使用 切片语法 选择节:
:sections[1:]
包括除第一个之外的所有节,:sections[:last]
包括除最后一个之外的所有节,:sections[last]
仅包括最后一个节,:sections[1:2]
包括第 2 和第 3 个节。请注意,此切片访问不会抛出任何越界错误,因此您不必非常精确。 :title
- 在 front matter 中定义的标题,否则为自动标题。Hugo 会为没有文件支持的节、分类法和术语页面自动生成标题。
:slug
- 在 front matter 中定义的 slug,否则为在 front matter 中定义的标题,否则为自动标题。Hugo 会为没有文件支持的节、分类法和术语页面自动生成标题。
:filename
- 内容的无扩展名文件名,适用于
page
页面类型。 :slugorfilename
- 在 front matter 中定义的 slug,否则为内容的无扩展名文件名,适用于
page
页面类型。
对于与时间相关的值,您还可以使用 Go 的 time 包中定义的布局字符串组件。例如
permalinks:
posts: /:06/:1/:2/:title/
[permalinks]
posts = '/:06/:1/:2/:title/'
{
"permalinks": {
"posts": "/:06/:1/:2/:title/"
}
}
外观
URL 的外观要么是丑陋的,要么是漂亮的。
类型 | 路径 | URL |
---|---|---|
丑陋 | content/about.md | https://example.org/about.html |
漂亮 | content/about.md | https://example.org/about/ |
默认情况下,Hugo 生成漂亮的 URL。要生成丑陋的 URL,请更改您的站点配置
uglyURLs: true
uglyURLs = true
{
"uglyURLs": true
}
您还可以按节启用 uglyURLs。例如,对于包含书籍和电影节的站点
uglyURLs:
books: true
films: false
[uglyURLs]
books = true
films = false
{
"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">
这是一种不完善的、蛮力的方法,可能会影响内容以及 HTML 属性。如上所述,这是一个遗留的配置选项,很可能会在未来的版本中删除。
要启用
canonifyURLs: true
canonifyURLs = true
{
"canonifyURLs": true
}
相对 URL
如果启用,Hugo 会在渲染页面后执行搜索和替换。它会搜索与 action
、href
、src
、srcset
和 url
属性关联的站点相对 URL(带有前导斜杠)。然后,它会将 URL 转换为相对于当前页面。
例如,在渲染 content/posts/post-1
时
<a href="/about"> → <a href="../../about">
<img src="/a.gif"> → <img src="../../a.gif">
这是一种不完善的、蛮力的方法,可能会影响内容以及 HTML 属性。如上所述,除非您正在创建无服务器站点,否则不要启用此选项。
要启用
relativeURLs: true
relativeURLs = true
{
"relativeURLs": true
}
别名
使用别名从旧 URL 创建到新 URL 的重定向
- 带有前导斜杠的别名相对于
baseURL
- 不带前导斜杠的别名相对于当前目录
示例
更改现有页面的文件名,并从之前的 URL 创建到新 URL 的别名
aliases:
- /posts/previous-file-name
aliases = ['/posts/previous-file-name']
{
"aliases": [
"/posts/previous-file-name"
]
}
每个这些目录相对别名都等效于上面的站点相对别名
previous-file-name
./previous-file-name
../posts/previous-file-name
您可以为当前页面创建多个别名
aliases:
- previous-file-name
- original-file-name
aliases = ['previous-file-name', 'original-file-name']
{
"aliases": [
"previous-file-name",
"original-file-name"
]
}
在多语站点中,使用目录相对别名,或者在站点相对别名中包含语言前缀
aliases:
- /de/posts/previous-file-name
aliases = ['/de/posts/previous-file-name']
{
"aliases": [
"/de/posts/previous-file-name"
]
}
别名如何工作
使用上面的第一个示例,Hugo 会生成以下站点结构
public/
├── posts/
│ ├── new-file-name/
│ │ └── index.html
│ ├── previous-file-name/
│ │ └── index.html
│ └── index.html
└── index.html
从之前的 URL 到新 URL 的别名是一个客户端重定向
<!DOCTYPE html>
<html lang="en-us">
<head>
<title>https://example.org/posts/new-file-name/</title>
<link rel="canonical" href="https://example.org/posts/new-file-name/">
<meta name="robots" content="noindex">
<meta charset="utf-8">
<meta http-equiv="refresh" content="0; url=https://example.org/posts/new-file-name/">
</head>
</html>
总而言之,head
部分中的元素
- 告诉搜索引擎新的 URL 是规范的
- 告诉搜索引擎不要索引之前的 URL
- 告诉浏览器重定向到新的 URL
Hugo 会在渲染页面之前渲染别名文件。具有之前文件名的新页面会按预期覆盖别名。
自定义
要覆盖 Hugo 的嵌入式 alias
模板,请将 源代码复制到 layouts
目录中具有相同名称的文件中。该模板接收以下上下文
- 永久链接
- 到被别名的页面的链接。
- 页面
- 被别名的页面的页面数据。