URL 管理
概述
默认情况下,当 Hugo 渲染页面时,生成的 URL 与 content
目录中的文件路径匹配。例如:
content/posts/post-1.md → https://example.org/posts/post-1/
您可以使用前置 matter 值和站点配置选项来更改 URL 的结构和外观。
前置 matter
slug
在 front matter 中设置 slug
以覆盖路径的最后一部分。 slug
值不影响章节页面。
---
slug: my-first-post
title: 我的第一篇文章
---
+++
slug = 'my-first-post'
title = '我的第一篇文章'
+++
{
"slug": "my-first-post",
"title": "我的第一篇文章"
}
生成的 URL 将是:
https://example.org/posts/my-first-post/
url
在 front matter 中设置 url
以覆盖整个路径。将其与常规页面或章节页面一起使用。
如果您在 front matter 中同时设置 slug
和 url
,则 url
值优先。
包含冒号
New in v0.136.0如果您需要在 url
front matter 字段中包含冒号,请使用反斜杠字符对其进行转义。如果将字符串用单引号括起来,则使用一个反斜杠;如果将字符串用双引号括起来,则使用两个反斜杠。对于 YAML front matter,如果您省略引号,则使用单个反斜杠。
例如,使用此 front matter:
---
title: 示例
url: my\:example
---
+++
title = '示例'
url = 'my\:example'
+++
{
"title": "示例",
"url": "my\\:example"
}
生成的 URL 将是:
https://example.org/my:example/
如上所述,这在 Windows 上会失败,因为冒号( :
)是保留字符。
文件扩展名
使用此 front matter:
---
title: 我的第一篇文章
url: articles/my-first-article
---
+++
title = '我的第一篇文章'
url = 'articles/my-first-article'
+++
{
"title": "我的第一篇文章",
"url": "articles/my-first-article"
}
生成的 URL 将是:
https://example.org/articles/my-first-article/
如果您包含文件扩展名:
---
title: 我的第一篇文章
url: articles/my-first-article.html
---
+++
title = '我的第一篇文章'
url = 'articles/my-first-article.html'
+++
{
"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/ |
前置 matter 中的永久链接标记
New in 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
- 前置 matter
date
字段中定义的 4 位数年份。 :month
- 前置 matter
date
字段中定义的 2 位数月份。 :monthname
- 前置 matter
date
字段中定义的月份名称。 :day
- 前置 matter
date
字段中定义的 2 位数日期。 :weekday
- 前置 matter
date
字段中定义的一位数星期几(星期日 = 0)。 :weekdayname
- 前置 matter
date
字段中定义的星期几名称。 :yearday
- 前置 matter
date
字段中定义的 1 到 3 位数的年份日数。 :section
- 内容的部分。
:sections
- 内容的部分层次结构。您可以使用 切片语法 选择部分部分:
:sections[1:]
包含除第一个以外的所有部分,:sections[:last]
包含除最后一个以外的所有部分,:sections[last]
只包含最后一个部分,:sections[1:2]
包含部分 2 和 3。请注意,此切片访问不会引发任何越界错误,因此您不必精确。 :title
- 前置 matter 中定义的标题,否则为自动标题。Hugo 为非文件支持的章节、分类和术语页面自动生成标题。
:slug
- 前置 matter 中定义的 slug,否则为前置 matter 中定义的标题,否则为自动标题。Hugo 为非文件支持的章节、分类和术语页面自动生成标题。
:filename
- 内容的文件名(不含扩展名),适用于
page
页面类型。 :slugorfilename
- 前置 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(那些带有前导斜杠的 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)。然后它将 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
模板,请将 源代码 复制到布局目录中具有相同名称的文件中。模板接收以下上下文:
- 永久链接
- 被创建别名的页面的链接。
- 页面
- 被创建别名的页面的页面数据。