安全加固 + 结构清理:修注入/串写/竞态,DOMPurify 上线,后端补事务与 handler 测试
后端: - ORDER BY 白名单(sanitizeOrder)堵住 ?order= SQL 注入,补回归测试 - 登录限速(每 IP 10 次失败/10 分钟 429)、TLS/反代下 Secure cookie、NewAPI 构造器 - Delete/setTags/MergeTags/DeleteTag 包事务;Archive 去 500 篇上限 - 列表接口裁剪:不传 content_md,长文 content_html 截 600,新增 content_len;health 探 DB 前端: - EditorView 路由复用串写修复(RouterView :key + sync watch 回写原文章) - v-html 出口统一过 DOMPurify(sanitizeHtml),stripTags 改 DOMParser - 列表竞态防护(Home/Tag/Posts 请求序号)、TagView 分页修复 - 侧栏接口 30s 缓存去重;one:unauthorized 监听器泄漏修复 - 删 styles.css 498 行重复块;移除 tailwind/marked/vue-tsc 死依赖;CommandPalette a11y 语义
This commit is contained in:
+20
-1
@@ -1,5 +1,23 @@
|
||||
const base = ''
|
||||
|
||||
// 侧栏数据(标签 / 最近更新)每页都会重新挂载请求,这里做 30s 的
|
||||
// 模块级缓存 + 并发去重;失败不缓存,下一次调用会重新请求。
|
||||
function cached(fn, ttl = 30000) {
|
||||
let p = null
|
||||
let at = 0
|
||||
return (...args) => {
|
||||
const now = Date.now()
|
||||
if (p && now - at < ttl) return p
|
||||
at = now
|
||||
const cur = fn(...args)
|
||||
p = cur
|
||||
cur.catch(() => {
|
||||
if (p === cur) p = null
|
||||
})
|
||||
return cur
|
||||
}
|
||||
}
|
||||
|
||||
async function request(path, { method = 'GET', body, auth = false } = {}) {
|
||||
const headers = { 'Content-Type': 'application/json' }
|
||||
const res = await fetch(base + path, {
|
||||
@@ -35,7 +53,8 @@ export const publicApi = {
|
||||
posts: (params = {}) => request('/api/posts?' + new URLSearchParams(params)),
|
||||
post: (slug) => request('/api/posts/' + encodeURIComponent(slug)),
|
||||
archive: () => request('/api/archive'),
|
||||
tags: () => request('/api/tags')
|
||||
tags: cached(() => request('/api/tags')),
|
||||
latest: cached(() => request('/api/posts?size=5'))
|
||||
}
|
||||
|
||||
export const adminApi = {
|
||||
|
||||
Reference in New Issue
Block a user