【问题标题】:How to make and store slug for post title?如何制作和存储帖子标题的slug?
【发布时间】:2016-10-24 12:39:09
【问题描述】:

我使用 MongoDB/mongoose 来存储具有以下架构的博客文章:

PostSchema = mongoose.Schema({
   title: {type: String},
   body: {type: String}
});

现在我的帖子网址如下所示:http://www.example.local/posts/571f78d077b4454bafcfcced

我希望我的帖子包含如下内容: http://www.example.local/posts/571f78d077b4454bafcfcced/how-to-make-and-store-slug-for-title

所以我的问题是:

  1. 我应该生成一次 slug 并存储在 PostModel 架构中还是在显示的每个帖子上生成?
  2. 如何根据标题(现有节点模块解决此任务)为非 ASCII 字符生成 slug?
  3. 我应该使用哪个位置将查询从 http://www.example.local/posts/571f78d077b4454bafcfcced 重定向到 http://www.example.local/posts/571f78d077b4454bafcfcced/how-to-make-and-store-slug-for-title(nodejs、nginx、客户端)。

谢谢!

EIDT:我还发现,在StackOverflow Database viwer 中,ID 为 503429 SO 的问题存储了非 slugged 标题。那么这是否意味着每次请求问题时SO都会计算slug?

【问题讨论】:

  • 可以使用npm包mongoose-url-slugs
  • 那么如果回答我的第一个问题mongoose-url-slugs 将 slug 存储在 MongoDB 文档中?
  • 可以选择将 slug 作为密钥存储在 MongoDB 文档中,例如PostSchema.plugin(URLSlugs('title', {field: 'myslug'}));
  • 我明白了,我对它在引擎盖下的工作原理很感兴趣

标签: node.js mongodb mongoose seo slug


【解决方案1】:

1.我应该生成一次 slug 并存储在 PostModel 架构中还是在显示的每个帖子上生成?

这两种方法都有效且各有优点:

  • 数据库:更快,因为我们不需要每次需要时都生成它。 Slug 只会生成一次。
  • 即时:如果您决定更改模式/算法(无论如何都应该避免),我们不需要重新生成整个表或数据库信息。数据库中使用的空间更少,数据库和应用程序之间传输的数据更少。不应该花费太长时间,除非您的生成 slug 的算法性能不佳,但在这种情况下,生成时间应该不是问题。

在这两种情况下,您都必须选择一个模式并定义一个算法来生成与您选择的模式匹配的 slug。

我个人几乎总是选择将 slug 存储在数据库中,这样您就可以为特定帖子指定一个 slug。你可能永远不需要这样做,但如果出现这种情况,你就准备好了。 例如,如果对于特定帖子,生成的 slug 将是 awesome-post,而您希望它是 best-awesome-post,如果 slug 存储在数据库中,您可以轻松完成,否则您将不得不调整您的算法对于每一个“特殊”案例,这将成为一个拥有多个类似案例的噩梦。

我认为有利于存储它的另一点:一旦你发布了一篇文章,slug 就是这篇文章的永久链接的一部分,它应该被认为是不可变的。如果在这种情况下可以避免,我不喜欢生成多次不可变数据。

2.如何根据标题(现有节点模块解决此任务)为非 ASCII 字符生成 slug?

正如你所说,存在多个节点模块以基于一个或多个字段(如标题)生成 slug,有些甚至与 MongoDB/Mongoose 集成,如 mongoose-url-slugs

在大多数 slug 中,重音字符将被转换为它们的非重音字符,所有内容都转换为小写,标点符号被删除,空格被替换为 -,等等。

关于您问题的 ASCII 部分,例如,如果您查看 mongoose-url-slugs 的代码,在生成 slug 时,他们会调用 removeDiacritics 函数,该函数将去除这些特殊字符并用 slug 替换它们- 友好的等价物。

我能想到的一个需要特殊处理才能正确处理的例子是德语中的“道路”一词:“Straße”。

该函数将识别 Eszett 字符 (\u00DF) 并将其替换为字母“s”。

如果您想领先一步,您应该使用处理 unicode 和 utf-8 的 slug 模块,例如 slug,它符合关于统一资源标识符 (URI) 的 RFC 3986

它会将i ♥ my title 之类的标题转换为i-love-my-title 等。

3.我应该使用哪个位置将查询从 http://www.example.local/posts/571f78d077b4454bafcfcced 重定向到 http://www.example.local/posts/571f78d077b4454bafcfcced/how-to-make-and-store-slug-for-title(nodejs、nginx、客户端)。

如果您出于我上面发布的原因将 slug 存储在数据库中,那么 slug 应该只生成一次,然后保存在数据库中。此时,服务器端或客户端不应再进行重新生成。

在客户端显示链接时,您将始终安全地使用之前生成的 slug,例如 http://www.example.local/posts/571f78d077b4454bafcfcced/how-to-make-and-store-slug-for-title 以按照您想要的模式显示链接。

如果客户端使用没有 slug 的 url 或像 http://www.example.local/posts/571f78d077b4454bafcfcced/how-to-make 这样的部分 slug,使用完整的 slug 重定向到正确的 url,Stack Overflow 在这个特定问题上是一个很好的例子,他们只是发送一个301重定向到正确的url。

他们应该在服务器上处理这些特殊情况,因为您在服务器上的应用程序是唯一有权处理此问题的应用程序(如果您将 slug 保存在数据库中)。您的应用程序知道数据库中特定帖子的正确 slug,因此如果未指定 slug 或只是部分的,这很容易在您的应用程序中检测到,您可以安全地触发 301 重定向到正确的 URL蛞蝓,比如http://www.example.local/posts/571f78d077b4454bafcfcced/how-to-make-and-store-slug-for-title

您应该在您的 Node 应用程序中处理这些情况(我假设您正在使用问题中提到的 Node)并在需要时重定向到正确的 URL。

例如:

res.writeHead(301, { "Location": `http://www.example.local/posts/${postId}/${postSlug}` });

由于可以通过多个 URL 访问相似的内容,您还应该使用规范链接元素来指定搜索引擎应该使用的“规范”URL,例如避免重复内容问题。

<link rel="canonical" href="http://www.example.local/posts/571f78d077b4454bafcfcced/how-to-make-and-store-slug-for-title">

关于您对Stack Exchange Data Explorer 的编辑,我认为他们在结果中省略了该字段,因为它并不那么重要。根据a comment from Nick Craver, Software Developer and Systems Administrator for Stack Exchange 的说法,他们确实在检查他们在数据库中的 slugified 标题是否与查询中的标题匹配,如果不匹配,他们会重定向。

编辑 URL 中的俄语字符:

如果你想保留例如俄罗斯字符,没问题,只要你跟上 utf-8 之类的。您的链接示例显示俄语字符,但在幕后 URL 是“百分比编码”或“url 编码”,您可以通过右键单击浏览器中的链接自行检查,选择“检查”,您会看到该 URL实际上类似于http://ru.stackoverflow.com/questions/456697/genymotion-%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%B0-%D0%BF%D1%80%D0%B8-%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B8-%D0%B2%D0%B8%D1%80%D1%82%D1%83%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B9%D1%81%D1%82%D0%B2%D0%B0。您的浏览器知道它是 url 编码的,并用俄语字符正确显示。

你当然有 Node.js 模块甚至是原生 Javascript 方法来对你想要的任何 URL 进行 url 编码。

如果您也想了解 SEO 和搜索引擎,例如 Google:“我们通常可以跟上 UTF-8 编码的 URL,我们通常会在搜索结果中向用户展示它们(但链接到您的服务器) URL 正确转义)”,所以完全没有问题。

大多数“slugifier”模块都会删除这些字符,所以如果你真的想保留它们,你必须使用更具体的东西,比如arSlugify

var ars = require('arslugify');

var title = 'genymotion ошибка при создании виртуального устройства';

var slug = ars(title);

var url = 'www.example.local/posts/571f78d077b4454bafcfcced/' + slug;
var encodedUrl = encodeURIComponent(url);

console.log(url);
// www.example.local/posts/571f78d077b4454bafcfcced/genymotion-ошибка-при-создании-виртуального-устройства
console.log(encodedUrl);
// www.example.local%2Fposts%2F571f78d077b4454bafcfcced%2Fgenymotion-%D0%BE%D1%88%D0%B8%D0%B1%D0%BA%D0%B0-%D0%BF%D1%80%D0%B8-%D1%81%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B8-%D0%B2%D0%B8%D1%80%D1%82%D1%83%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE-%D1%83%D1%81%D1%82%D1%80%D0%BE%D0%B9%D1%81%D1%82%D0%B2%D0%B0

【讨论】:

  • 感谢您的精彩回答。让我澄清一点。你很难过我可能会使用 node-slug 来生成符合 RFC 3986 的 URI。我需要生成带有非 ascii 字符的 url,就像 SO 那样。例如这里是 url ru.stackoverflow.com/questions/456697/… 中带有俄语字符的 url,我需要同样的
  • 我编辑了答案的底部,以提供一些关于 URL 中俄语字符的精确度,例如,对于简单的评论来说有点太长了。
  • 谢谢,所以我需要在通过node-slug 处理之前使用encodeURIComponent('genymotion-ошибка-при-создании-виртуального-устройства') 吗?
  • 添加了一个新的代码示例来处理俄语字符,特别是在您想要保留它们的情况下,因为大多数 slug 工具都会删除这些字符。
  • 感谢您的精彩而完整的回答!
猜你喜欢
  • 2011-09-19
  • 2021-01-30
  • 2017-06-01
  • 2020-04-15
  • 2016-10-28
  • 2018-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多