非英文文件名识别
本博客中文文件名 404 问题的原因与解决方案
问题描述
在博客项目中,添加一个文件名包含中文的 markdown 文档(如 中文识别.md),首页列表可以正常显示文章的 title、excerpt 等信息,但点击卡片进入文章详情页时显示 404。
问题原因
URL 编码机制
当文件名包含非 ASCII 字符(如中文)时,浏览器会自动对 URL 进行编码。例如:
- 原始 slug:
中文识别 - 编码后 URL:
/post/%E4%B8%AD%E6%96%87%E8%AF%86%E5%88%AB
匹配失败
在 getPostBySlug 函数中,传入的 slug 参数可能是 URL 编码后的字符串 %E4%B8%AD%E6%96%87%E8%AF%86%E5%88%AB,但文件系统中的实际文件名是 中文识别.md。
当使用编码后的 slug 去匹配文件名时:
const targetFileName = `${slug}.md` // "%E4%B8%AD%E6%96%87%E8%AF%86%E5%88%AB.md"
// 实际文件名: "中文识别.md"
// 匹配失败 → 返回 null → 触发 404
解决方案
在 getPostBySlug 函数中,使用 decodeURIComponent() 对 slug 进行解码:
export const getPostBySlug = (slug: string): Post | null => {
ensurePostsDirectory()
// 解码 URL 编码的 slug(处理中文等非 ASCII 字符)
const decodedSlug = decodeURIComponent(slug)
const fullPath = findPostPathBySlug(decodedSlug)
// ...
}
为什么这样有效
- 如果 slug 是编码后的
%E4%B8%AD%E6%96%87%E8%AF%86%E5%88%AB,decodeURIComponent会将其解码为中文识别 - 如果 slug 已经是解码后的
中文识别,decodeURIComponent不会改变它(幂等性)
这样无论 Next.js 传入的是编码还是解码后的 slug,都能正确匹配到文件。
相关参考
encodeURIComponent vs decodeURIComponent
encodeURIComponent(): 将字符串编码为 URI 组件,中文等特殊字符会被转换为%XX格式decodeURIComponent(): 将编码后的 URI 组件解码回原始字符串