URL slug 生成器,免费

将任意文本转换为 URL 兼容的 slug。

仅在浏览器,你的文本永远不会离开你的设备


什么是 URL slug?

slug 是页面标题的 URL 版本。它是 URL 中以人类可读的形式标识页面的部分。例如,在 example.com/blog/my-awesome-article 中,slug 是「my-awesome-article」。

好的 slug 只使用小写字母、数字和连字符。它们会移除重音、特殊字符和多余空格。这既改善 SEO,也改善用户体验 · 搜索引擎和人类都能读懂 URL 并理解页面内容。

这个词的来历,19 世纪的报社编辑部

这个词比 Web 早了一个世纪。在 Linotype 时代的排字房里,每一行铅字都被铸成一条单独的金属条(一个「slug」)大约三十派卡宽,在铅里大约重十二盎司。这个词后来漂移到指代编辑写在一篇稿件顶部、以便在生产流程中标记它的简短标识符:一个一两词的 handle,比如 mayor-budgetschool-fire,记者、副编辑和印刷工人无需打出完整大标题,就能用它互相提及这则稿件。AP 与各大日报的体例手册到现在还记录着这种用法。

当 Movable Type、WordPress 与早期 Django 文档在 2000 年代初采用「slug」作为字段名时,他们是把报社的术语原封不动地借了过来。Django 的文档至少从 2005 年的 0.91 版开始就把这个字段叫做 slug,定义现在已是规范级:一个简短标签,只包含字母、数字、下划线或连字符,通常用于 URL。这个比喻之所以恰到好处,是因为铅铸的 slug 与 URL 中的 slug 都是简短、独特、机器友好的 token,指向某个更长的东西。

RFC 3986 与未保留字符集

URL 语法由 RFC 3986(「统一资源标识符(URI):通用语法」)定义,2005 年 1 月由 Tim Berners-Lee、Roy Fielding 和 Larry Masinter 发布,取代 RFC 2396 和 2732。它是 STD 66 互联网标准,即 IETF 的最高成熟度等级,只授予经过验证、稳定且被广泛实现的协议。RFC 3986 第 2.3 节定义了非保留字符,也就是在任何 URI 组件中都无需百分号编码、保证安全的唯一一批字符:A-Za-z0-9、连字符、句点、下划线和波浪号。总共六十六个字符。其余字符要么是保留字符(在某些 URI 组件中有结构含义),要么属于「其他」,后一类只要出现在 URI 中就必须百分号编码。

因为未保留集是唯一一个能保证在历史上写过的每一个 URI 解析器中干净往返的字符集,各种 slug 生成器收敛到一条几乎相同的流水线:把字母字符变小写,保留数字,保留连字符,把空白替换为单个连字符,然后对其他所有内容,要么剥掉要么音译。下划线、句点和波浪号在技术上是允许的,但在 slug 中按惯例避开,句点会与文件扩展名冲突,波浪号在旧 URL 习惯里被读成主目录,而下划线由于下面要谈到的 SEO 原因败给了连字符。

「Cool URIs Don’t Change」,Berners-Lee,1998

Tim Berners-Lee 1998 年的风格说明《Cool URIs Don’t Change》,托管在 W3C 网站上,是 slug 哲学被引用得最多的一篇文章。开头一句很有名:酷的 URI 是不会变的。文章接下来读起来像是一篇反对那种把临时实现细节烤进路径里的 URL 设计的檄文。它推荐的「不要做」清单影响了 slug 实践近三十年:不要把作者工具的扩展名放进 URL(它们泄露实现,迁移时就坏掉;不要把状态放进 URL)页面会从「当前」中退出,但 URL 不应当;不要放作者名字,作者会换;不要放日期,除非日期对资源本身是基础的;不要把会话 ID、查询参数或登录状态放进规范URL。

Slug(那些描述性的、语义性的小写带连字符的词)正是「酷」URI 中允许的部分。其他一切都是不该渗到地址里去的结构性装饰。WordPress 的固定链接设计、Django 的 SlugField 与 Rails 的 to_param 都把这一指导内化:输出一条代表页面含义的 URL,而不是它如何被服务的那套机制。

连字符胜过下划线,而且有据可查

在 2005 年的 WebmasterWorld 访谈中,Google 工程师 Matt Cutts 说连字符被 Google 的 tokenizer 当作词分隔符,而下划线是词连接符。所以 green-apples 被读作两个 token greenapples,而 green_apples 被读作单个 token green_apples。对于查询 「green apples」,带连字符的 URL 会匹配标题关键词检查;带下划线的不会。Cutts 在 2007 年的博客上以及 2011 年 YouTube 上的 Google Webmaster Help 视频(《Underscores vs. dashes in URLs》)里又重申了这一点,并指出Google 一度评估过把下划线行为也改为分隔符,但没有这么做,因为那会破坏太多刻意把下划线当作连接符使用的现有 URL(__init__.py、编程函数名等)。

Google 现在的「URL structure best practices for Google Search」页面直接推荐连字符:/green-dress.html 这样的 URL 比 /greendress.html 更有用,而且应该用连字符而不是下划线。这条建议已被持续记录了二十多年。每一条 URL 上的影响很小,但跨数千页的网站会累积起来,而把连字符换成下划线没有任何上行收益,没有任何 SEO 场景下下划线胜出。每一份靠谱的 slug 指南都以同一句话结束:用连字符。

Unicode 归一化,NFD 如何剥掉重音

Unicode 标准为很多带重音的字符定义了两种编码方式:预组合(单个码位,é 是 U+00E9)与分解(基础字母后接组合标记,é 是 U+0065 加 U+0301,即组合锐音符)。视觉相同,字节不同。Unicode Technical Standard #15 定义了四种归一化形式(NFC、NFD、NFKC、NFKD)而对于 slug 生成,NFD 是抓手。如果你拿一段输入字符串,归一化到 NFD,然后把 Unicode 范围 U+0300 到 U+036F(组合附加符号块)中的每一个码位都剥掉,你就得回到了基础 ASCII 字母。Café 变成 cafe,naïve 变成 naive,François 变成 Francois,niño 变成 nino,crème brûlée 变成 creme brulee

NFD 不会折叠那些不能分解为「基础+标记」的字符。德语 ß(锐音 s)在 NFD 下不会分解为 ss,它需要显式音译。波兰语 ł(带杠的 l)不会分解为 l。挪威语 ø 不会分解为 o。冰岛语 þ(thorn)与 ð(eth)需要查表。浏览器从大约 2015 年起原生支持 String.prototype.normalize()(Chrome 34、Firefox 31、Safari 10),所以即便是很小的 JavaScript slugify 工具,不靠库也能完成剥重音的工作。

slugify 库家族,每个生态各自给出什么

Django 的 django.utils.text.slugify() 自 2000 年代初就在这个 Python 框架中。它把字符变小写,剥掉不属于 [A-Za-z0-9_-] 的字符,把空白替换为连字符。从 Django 1.9(2015)开始,关键字 allow_unicode=True 会切换到一个 Unicode 感知模式,保留非 ASCII 字母。这是别人都在抄的参考实现。在 Node.js 里,Sindre Sorhus 的 @sindresorhus/slugify 是 npm 上下载量最大的 slugify 包,每周数百万次下载,特性包括人类可读分隔符、可定制替换(可以把 & 映射为 and,把 @ 映射为 at)、Unicode 处理与 locale 感知的小写化(土耳其语带点/不带点 I,德语 ß → ss)。对于不使用 Django 的 Python 用户,Val Neekman 在 PyPI 上的 python-slugify 包装了 unidecode 音译库,并加入 slug 专属行为:正则切词、替换字符、最大长度、停用词去除。

其他生态遵循同一模式。PHP 在 Packagist 上有 Cocur 的 cocur/slugify,被 Laravel 与 Symfony 插件使用,而 Symfony 自己自 5.0 版起就在 symfony/string 中提供了一个 AsciiSlugger。Ruby on Rails 用 String#parameterize,这至少从 Rails 1.0 起就内建于 ActiveSupport 中;friendly_id gem 在其上叠加历史跟踪与冲突处理。Go 有 gosimple/slug,带有八十多种语言的 locale 表。Rust 有 slug crate。Java 有 Apache Commons Text 与 slugify-jvm。值得注意的是,API 是何等地相似:输入字符串进,slug 字符串出,选项也都是那几样,分隔符、最大长度、小写、locale。Absolutool 的工具属于同一家族,但完全运行在你的浏览器里,不需要安装任何库。

WordPress:43% 的 Web 跑着这条流水线

WordPress 是 Web 上最大的单一 slug 输出系统,按照 W3Techs 2026 年的调查,它支撑大约 43% 的网站,所以对大多数读者来说,它的 slug 习惯实际上就是 Web 的 slug 习惯。一旦保存一篇 post,WordPress 通过 sanitize_title()(在默认 rewrite 情况下会调用 sanitize_title_with_dashes())从标题自动生成 slug:小写化,剥 HTML,解码实体,把空白与多数标点替换为连字符,对不安全字符做百分号编码,合并相邻连字符,修剪首尾连字符。如果结果与某篇已有 post 的 slug 冲突,WordPress 会追加 -2-3,以此类推。Slug 在 post 编辑器里可以编辑,一篇 post 一旦发布,改 slug 就会让每一个现有链接断掉,除非编辑配置了一条重定向。WordPress 历史上默认不音译非 ASCII 字符;它对它们做百分号编码,产生了像 %D0%BF%D1%80%D0%B8... 这种有名的丑陋的西里尔 URL,Cyr-To-Lat 这类插件就是为修这个写出来的。

拉丁之外:为西里尔、CJK、阿拉伯做音译

NFD 只能处理那些能分解为 ASCII 基础 + 组合标记的字符。对于非拉丁脚本,slug 流水线需要音译,把每一个非拉丁字符映射到其拉丁文等价物。规范的 Python 库是 unidecode,最初是 Sean M. Burke 2001 年的 Perl Text::Unidecode 的移植,几乎把 Basic Multilingual Plane 中的每一个字符都映射成一个「最佳猜测」的 ASCII 字符串:Москва → MoskvaΑθήνα → Athena。CJK 的兜底是有争议的部分:unidecode 对所有 CJK 字符使用普通话拼音,因为中文有最大的 CJK 字符覆盖度,这对日文产生了荒谬的罗马化(東京 → 拼音里的 Dong Jing,而不是 Tokyo)。日语专用的工具如 pykakasi 才会把汉字 + 假名转换成正确的罗马字。International Components for Unicode(ICU)库,由 Unicode Consortium 与 IBM 维护,提供了一个 Transliterator API,带有像 Russian-Latin/BGN、Greek-Latin/UNGEGN 与 Han-Latin 这样的命名规则集,实现官方罗马化标准。Absolutool 的工具站在更轻的一端:它通过 NFD 折叠拉丁的变音符,把别的全部丢掉。想为俄文或中文标题生成 slug 的用户可以在把文本粘贴进来之前,先跑一次单独的音译步骤。

URL 长度限制,「2000 字符」规则的来历

RFC 3986 本身并没有规定长度限制,URI 语法是没有上限的。每一种限制都是工程上的。Internet Explorer 历史上把 URL 限定在 2,083 字符(这是烤进 Trident 引擎里的硬限),这就是被广泛引用的「2,000 字符」经验法则的来源。Chrome、Firefox、Safari 与现代 Edge 在地址栏里大约支持 64,000 到 100,000 以上字符的 URL。Apache 的 LimitRequestLine 默认对整个请求行设为 8,190 字节;nginx 的 large_client_header_buffers 默认 8 KB;IIS 默认 URL 是 16,384 字节、查询字符串是 4,096 字节。RFC 9110(HTTP/1.1,2022)在 §4.1 建议服务器「ought to be capable of handling URIs of length 8,000 octets or longer」,但没有强制规定上限。对 slug 来说,关键是它们按惯例都是短的(三到七个词,三十到六十字符)为了 SEO 和可分享性。Google 的 John Mueller 在多次 Webmaster Hangout 中说过,URL 长度本身不是排名信号,但过长的 URL 可能在搜索结果摘要中被截断,影响点击率,在社交分享中显得不专业。多数 slug 生成器因此会暴露一个最大长度选项;这一款默认无限制,允许你自己设定上限。

停用词去除:密集 vs 合乎语法

许多 slugify 库提供可选的停用词去除,在拼装 slug 之前丢弃常见短词(aantheofisandortoinforon)。理由是它们带不来任何 SEO 信号,反而把 URL 撑长。所以 「The Best Way to Make a Cup of Tea」 会变成 best-way-make-cup-tea(5 个 token,24 个字符),而不是 the-best-way-to-make-a-cup-of-tea(10 个 token,35 个字符)。代价:更短更密,但偶尔会出现语法塌陷(how-to-be-good 被剥成 how-good 失去了意思),也有把真正承担意图的词去掉的风险(art-of-war 被剥成 art-war)。WordPress 默认不去除停用词(这是一种插件 opt-in 行为)大多数现代 slug 生成器也都把它默认关掉、做成一个复选框。WordPress 的 Yoast SEO 把含停用词的 slug 标记为一个轻微的建议,而不是错误。本生成器不会自动去除停用词,理由是发布者比一份静态词表更清楚标题的意图。如果你想让它们消失,直接编辑输出就好。

Slug 冲突:当两篇 post 共享一个标题时,CMS 怎么办

当两篇 post 自动生成同一个 slug(「My Post」「My-Post!」都产生 my-post)系统就必须解决冲突。最常见的策略:数字后缀(my-post-2my-post-3)(可预测,永不冲突,但后缀本身没有任何语义差异;日期前缀(2026-04-27/my-post))对博客内容效果好,是 Jekyll、Hugo 和大多数新闻站点的默认;作者后缀(my-post-jane)(被Medium 与多作者博客使用;随机哈希后缀(my-post-a3f9))被 Stack Overflow、Notion 与短链系统使用,用人类可读性换取了保证唯一;或者发布时手工编辑,编辑上很干净,但很少作为默认,因为它会打断流程。对大多数 CMS 来说,务实的选择是数字后缀+手工编辑这个逃生口。带日期前缀的固定链接对那种以时间为锚的内容(日期是有意义的信息)很受欢迎。

SEO 影响:Slug 作为微小但可见的信号

Google 的排名文档把 URL 结构列为一个次要排名信号(页面内容、反向链接、用户互动信号与时新性都比它权重更高。但 URL 中的词确实有贡献,而且贡献是看得见的。Slug 词出现在 SERP 摘要中标题下面那行 URL 里,这影响点击率,即便 slug 本身并没被排序进去。Slug 词在 SERP 中如果与用户查询匹配,可能会被加粗)额外的视觉权重。内部和外部链接的锚文本在没有提供链接文本时,常常默认就是 URL,所以一个语义化的 slug 就成了链接文本,把它的关键词通过入站链接的 link equity 带进来。各家发布者的 A/B 测试一致地表明,描述性 slug 相比不透明 ID 把 CTR 提升了个位数百分比。Backlinko 2020 年的排名因素研究(分析了 118 万次 SERP)发现,在 SERP 顶部,短 URL 略微胜过长 URL。

「关键词越多越好」这个直觉有一个例外:关键词堆砌。2012 年 9 月的 Exact-Match Domain(EMD)更新专门对低质量的 exact-match 域名和 slug 减分(cheap-life-insurance.com/buy-cheap-life-insurance),Google 之后也一直在 URL 中对关键词堆砌打折扣。2026 年的结论:slug 中出现关键词有适度帮助;堆砌关键词反而有害。从 slug 拿到的最大单一 SEO 收益是发布之后不去改它。入站链接是积累在某条 URL 上的。页面权威是按 URL 级别复利的。一条 301 重定向能保留大部分但不是全部 link equity,而且只有当发布者真的设置了重定向才有效,很多人不会。Berners-Lee 的「Cool URIs Don’t Change」忠告对 SEO 有直接后果:每一次 slug 的更改,即便配了重定向,也会损失一小部分权威,需要时间才能恢复回来。

slug 的 SEO 最佳实践

常见问题

支持带重音的字符吗?

支持。生成器使用 Unicode 规范化(NFD)来移除重音。例如「cafe」仍为「cafe」,而「café」也会变成「cafe」。这确保 slug 干净且为纯 ASCII。

应使用连字符还是下划线?

SEO 推荐使用连字符。Google 的官方文档确认,URL 中的连字符会被视为单词分隔符,而下划线不会。所以「my-article」被读作两个词,而「my_article」只是一个词。

emoji 与符号会怎样?

emoji 不在 URL 未保留字符集中,NFD 也不会分解它们,它们没有拉丁字母等价物。本生成器会把它们丢掉。其他工具会对 emoji 做百分号编码(把单个字符变成像 %F0%9F%94%A5 这样的长字符串),这在现代浏览器里技术上是可行的,但会在分析工具、社交分享与邮件预览里产生不可读的 URL。多数 slug 指南都建议把 emoji 直接剥掉;如果你想保留它们,在 slug 步骤之前先做百分号编码。

这个工具会处理俄文、中文或阿拉伯文标题吗?

靠它自己不会。NFD 只折叠拉丁字符的重音;它没法把西里尔、希腊、阿拉伯、希伯来或 CJK 文字音译成拉丁文。把一段俄文或中文标题粘到本工具里,会把那些字符全部丢掉,产出一个空的或几乎空的 slug。正确的工作流是先跑一次音译(Python 的 unidecode、JavaScript 的 transliteration npm 包,或者维基百科的罗马化习惯)再把罗马化结果贴到这里。具体到日文,请用一个 kana 感知的工具,比如 pykakasi:通用的 CJK 音译器会用普通话拼音,把 東京 输出成 Dong Jing,而不是 Tokyo

如果发布之后我需要改一条 slug 怎么办?

在改 slug 之前,先把旧 URL 设一条 301 跳转到新 URL。一个 301(「Moved Permanently」)能保住老 URL 上积累的大部分 link equity,并告知爬虫与浏览器更新它们的书签。没有重定向的话,所有现有的入站链接都会断,你也会丢掉那些链接所代表的页面权威。即便配了重定向,也会损失一小部分 equity,需要数周或数月才能恢复回来。Berners-Lee 的格言(cool URIs don’t change)一半是审美,一半是 SEO 真相:每一次 slug 更改都要付代价,所以值得第一次就把 slug 写对。

有推荐的 slug 长度吗?

惯例是三到七个词,大约三十到六十个字符。足够长以做到描述性,足够短以让 Google 的 SERP 摘要不去截断它,人也能一眼把握话题。没有什么硬性的技术上限(RFC 3986 没有规定,现代浏览器能处理几万字符的 URL)但 Apache、nginx 与 IIS 在 KB 级别上有实际上限,而源自 Internet Explorer 的旧「2,000 字符」规则至今仍被作为安全的跨平台天花板引用。这里的「最大长度」选项可让你给输出设个上限;设为 0 表示不限。

我的文本会被保存或发送到任何地方吗?

不会。这个变换完全靠 JavaScript 内置的 String.prototype.normalize() 方法在你的浏览器中运行(Chrome 34、Firefox 31、Safari 10 起即支持(大约是 2015 年)。什么都不会上传,不会调用任何 API,不会写任何日志。你可以在生成 slug 时打开浏览器的 DevTools Network 面板自己验证)根本没有外发请求。这个页面对从未发布的标题、内部文档、草稿 post 等任何你不希望离开自己设备的内容派生出来的 slug,都是安全的。

相关工具