fix(blog): tags 双重编码导致详情页 500 + 上传文件名去中文

问题:
- 管理后台编辑博客保存后,访问 /blog/{slug} 返回 500
- 用户上传封面图后前端不识别/裂图

根因:
1. admin [id].get.js 原样返回 DB 里的 tags 字符串 "[]",编辑页 loadItem
   透传到 form.tags,保存时 JSON.stringify 再编码一次 → DB 写入 '"[]"'。
   公开接口 JSON.parse 后得到字符串 "[]" 而非数组,前端 tags.join(',')
   对字符串调用 → TypeError → SSR 500。
2. 上传接口保留中文文件名(\u4e00-\u9fa5 正则放行),Nginx/Nuxt 静态服务
   对含中文 URL 处理不一致,静态请求 404。

修复:
- admin GET:tags 统一解析为数组返回
- admin POST/PUT:只接受数组,非数组写入空数组
- 公开 /api/content/blog|news:safeParseTags 兼容历史脏数据,
  即使 DB 里是 '"[]"' / 非法 JSON 也保证输出数组
- upload.post.js:safeName 只保留 ASCII 字母数字,去除中文
- scripts/fix-articles-tags.mjs:一次性清理历史双重编码数据
这个提交包含在:
wx
2026-04-20 13:21:04 +08:00
父节点 f91ecbb093
当前提交 61c94b741e
共修改 6 个文件,包含 78 行新增和 8 行删除
+48
查看文件
@@ -0,0 +1,48 @@
/**
* 修复 articles 表 tags 字段被双重/三重 JSON.stringify 污染的历史数据
*
* 背景:
* admin 后台编辑文章时,loadItem 把 DB 里 tags 字段(字符串 "[]")
* 直接透传到 form.tags,保存时 JSON.stringify(form.tags) 导致双重编码,
* 形如 '"[]"' / '"\\"[]\\""'。公开接口 JSON.parse 后得到字符串而非数组,
* 前端 `tags.join(',')` TypeError → 页面 500。
*
* 本脚本把所有非数组 JSON 的 tags 统一重置为 '[]'。
*
* 运行: node scripts/fix-articles-tags.mjs
* 生产部署后执行一次即可(幂等)。
*/
import Database from 'better-sqlite3'
import { dirname, join } from 'path'
import { fileURLToPath } from 'url'
const __dirname = dirname(fileURLToPath(import.meta.url))
const dbPath = process.env.DB_PATH || join(__dirname, '..', 'hulai-website.db')
const db = new Database(dbPath)
const rows = db.prepare('SELECT id, slug, tags FROM articles').all()
let fixed = 0
const update = db.prepare('UPDATE articles SET tags = ? WHERE id = ?')
for (const r of rows) {
let ok = false
if (r.tags) {
try {
const v = JSON.parse(r.tags)
ok = Array.isArray(v)
} catch {}
} else {
ok = true // null / 空字符串:稍后统一写成 []
}
if (!ok) {
update.run('[]', r.id)
fixed++
console.log(`fixed id=${r.id} slug=${r.slug} old=${JSON.stringify(r.tags)}`)
}
}
console.log(`\nDone. scanned=${rows.length} fixed=${fixed}`)
db.close()