URL管理
概述
默认情况下,当Hugo渲染页面时,生成的URL与content
目录中的文件路径相匹配。例如:
content/posts/post-1.md → https://example.org/posts/post-1/
您可以使用前置数据的值和站点配置选项更改URL的结构和外观。
前置数据
slug
在前置数据中设置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
在前置数据中设置url
来覆盖整个路径。可以在普通页面和部分页面中使用。
使用以下前置数据:
---
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
加上语言前缀。
站点类型 | 前置数据url |
生成的URL |
---|---|---|
单语言 | /about |
https://example.org/about/ |
单语言 | about |
https://example.org/about/ |
多语言 | /about |
https://example.org/about/ |
多语言 | about |
https://example.org/de/about/ |
如果在前置数据中同时设置了slug
和url
,以url
的值为准。
站点配置
永久链接
在站点配置中为每个一级部分定义一个URL模式。每个URL模式可以针对给定的语言和/或页面类型进行定位。
在前置数据中设置的url
值会覆盖站点配置中定义的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模式时使用这些令牌。前置数据中的date
字段确定与时间相关的令牌的值。
:year
- 4位数年份
:month
- 2位数月份
:monthname
- 月份的名称
:day
- 2位数日期
:weekday
- 1位数星期几(星期日 = 0)
:weekdayname
- 星期的名称
:yearday
- 1至3位数的年份中的天数
:section
- 数据所属的部分
:sections
- 数据的部分层次结构。您可以使用 切片语法 选择部分,例如
:sections[1:]
包括除了第一个以外的所有部分,:sections[:last]
包括除了最后一个以外的所有部分,:sections[last]
仅包括最后一个部分,:sections[1:2]
包括第2至第3部分。请注意,切片访问不会抛出任何越界错误,因此您不必非常准确。 :title
- 数据的标题
:slug
- 数据的slug(如果在前置数据中未提供slug,则使用标题)
:slugorfilename
- 数据的slug(如果在前置数据中未提供slug,则使用文件名)
:filename
- 数据的文件名(不含扩展名)
对于与时间相关的值,您还可以使用Go的time package中定义的布局字符串组件。例如:
permalinks:
posts: /:06/:1/:2/:title/
[permalinks]
posts = '/:06/:1/:2/:title/'
{
"permalinks": {
"posts": "/:06/:1/:2/:title/"
}
}
外观
URL的外观可以是难看的(ugly)或者漂亮的(pretty)。
类型 | 路径 | 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
}
后处理
Hugo提供了两个互斥的配置选项,可以在渲染页面后更改URL。
规范化URLs
如果启用,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
}
相对URLs
如果启用,Hugo会在渲染页面后执行搜索和替换。它会搜索与action
、href
、src
、srcset
和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进行索引
- 告诉浏览器重定向到新URL
Hugo在渲染页面之前渲染别名文件。具有与前文件名相同的新页面将覆盖别名,正如预期的那样。
自定义
创建一个新的模板(layouts/alias.html
)来自定义别名文件的内容。该模板接收以下上下文:
Permalink
- 别名所指向的链接
Page
- 别名所指向页面的Page数据