如何为 post 标题制作和存储 slug?

How to make and store slug for post title?

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

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

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

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

所以我的问题是:

  1. 我应该生成一次 slug 并存储在 PostModel 模式中,还是在每个 post 显示时生成?
  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、client-side)。

谢谢!

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

1.我应该生成一次 slug 并存储在 PostModel 模式中还是在每个 post 显示时生成?

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

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

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

我个人几乎总是选择将 slug 存储在数据库中,这样您就可以为特定的 post 指定一个 slug。您可能永远不需要这样做,但如果出现这种情况,您就准备好了。 例如,如果对于特定的 post,生成的 slug 将是 awesome-post 而你希望它是 best-awesome-post,如果 slug 存储在数据库中,你可以很容易地做到这一点,否则您必须针对每个“特殊”情况调整您的算法,这将成为多个此类情况的噩梦。

还有一点我认为有利于存储它:一旦你发布一个 post,这个 slug 就是这个 post 的 permalink 的一部分,它应该是考虑免疫table。如果在这种情况下可以避免的话,我不太喜欢生成多次 immutable 数据。

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

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

在大多数 slug 中,重音字符将被转换为对应的 non-accented,所有内容都被转换为小写,标点符号被删除,例如 space 被替换为 -,等等.

关于你问题的 ASCII 部分,如果你看一下 mongoose-url-slugs for instance, when generating a slug, they call a removeDiacritics 函数的代码,它会去除这些特殊字符并用 slug-friendly 等效字符替换它们。

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

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

如果您想更进一步,您应该使用处理 unicode 和 utf-8 的 slug 模块,例如 slug for example which conforms to the RFC 3986 关于统一资源标识符 (URI)。

它将 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、client-side)。

如果您出于我上面 post 编辑的原因将 slug 存储在数据库中,则 slug 应该只生成一次,然后保存在数据库中。此时,server-side 或 client-side.

不应再发生重新生成

在 client-side 上显示 link 时,您将始终安全地使用之前生成的 slug,例如 http://www.example.local/posts/571f78d077b4454bafcfcced/how-to-make-and-store-slug-for-title 在 link 之后显示 link你想要的图案。

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

他们在服务器上处理这些特殊情况,因为它应该是因为您在服务器上的应用程序是唯一有权处理此事的应用程序(如果您在数据库中保存 slug)。您的应用程序知道特定 post 的正确 slug,因为它在数据库中,因此如果 slug 未指定或仅部分指定,这在您的应用程序中很容易检测到,您可以安全地触发 301 重定向到正确的URL 使用正确的 slug,例如 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 访问,您还应该使用规范 link 元素来指定搜索应该使用的“规范”URL例如避免重复内容问题的引擎。

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

关于您对 Stack Exchange Data Explorer, I think they're omitting the field from the results since it's not really that important. According to a comment from Nick Craver, Software Developer and Systems Administrator for Stack Exchange 的编辑,他们确实在检查他们在数据库中的标题是否与查询中的标题匹配,如果不匹配,他们将重定向。

编辑 URLs 中的俄语字符:

如果你想保留俄语字符或者例如,没问题,只要您跟上 utf-8 的步伐。您的 link 示例显示俄语字符,但在幕后 URL 是“percent-encoded”或“url-encoded”,您可以通过右键单击 [=123] 自行检查=] 在您的浏览器中,选择 Inspect,您会看到 URL 实际上类似于 http://ru.whosebug.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-encoded 并使用俄语字符正确显示它。

您当然有 Node.js 模块甚至本机 Javascript 方法来 url-encode 任何您想要的 URL。

如果您也对 SEO 和搜索引擎感到疑惑,Google 例如:“我们通常可以跟上 UTF-8 编码的 URLs,并且我们通常会将它们展示给我们搜索结果中的用户(但 link 到您的服务器并正确转义了 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