fix: 改进评论获取接口的slug规范化处理

修复当post_slug参数为根路径或包含查询参数/锚点时,slug列表生成逻辑不正确的问题。现在会先去除查询参数和锚点,然后正确处理根路径和带斜杠的变体。

新增单元测试验证各种slug格式的规范化行为,包括相对路径、完整URL和根路径。
This commit is contained in:
anghunk
2026-02-09 17:28:33 +08:00
parent 6d2e1659d0
commit a87fe373ca
2 changed files with 93 additions and 1 deletions

View File

@@ -0,0 +1,84 @@
import { describe, it, expect, vi } from 'vitest'
import { getComments } from './getComments'
describe('getComments slug normalization', () => {
const createMockContext = (slug: string) => {
const bindMock = vi.fn().mockReturnValue({
all: vi.fn().mockResolvedValue({ results: [] }),
first: vi.fn().mockResolvedValue(null)
})
const prepareMock = vi.fn().mockReturnValue({
bind: bindMock
})
const c = {
req: {
query: (key: string) => {
if (key === 'post_slug') return slug
return undefined
}
},
env: {
CWD_DB: {
prepare: prepareMock
}
},
json: vi.fn(),
executionCtx: {
waitUntil: vi.fn()
}
} as any
return { c, prepareMock, bindMock }
}
it('should query both variants for relative path without trailing slash', async () => {
const { c, bindMock } = createMockContext('/1.html')
await getComments(c)
// We expect the bind to be called with arguments including both variants
// The first call to bind should be for the main query (or we check all calls)
const calls = bindMock.mock.calls
const allArgs = calls.flat()
expect(allArgs).toContain('/1.html')
expect(allArgs).toContain('/1.html/')
})
it('should query both variants for relative path with trailing slash', async () => {
const { c, bindMock } = createMockContext('/1.html/')
await getComments(c)
const calls = bindMock.mock.calls
const allArgs = calls.flat()
expect(allArgs).toContain('/1.html')
expect(allArgs).toContain('/1.html/')
})
it('should query both variants for full URL', async () => {
const { c, bindMock } = createMockContext('https://example.com/foo')
await getComments(c)
const calls = bindMock.mock.calls
const allArgs = calls.flat()
expect(allArgs).toContain('https://example.com/foo')
expect(allArgs).toContain('https://example.com/foo/')
})
it('should handle root path correctly', async () => {
const { c, bindMock } = createMockContext('/')
await getComments(c)
const calls = bindMock.mock.calls
const allArgs = calls.flat()
expect(allArgs).toContain('/')
})
})

View File

@@ -30,7 +30,15 @@ export const getComments = async (c: Context<{ Bindings: Bindings }>) => {
slugList = Array.from(new Set([withSlash, withoutSlash]))
}
} catch {
slugList = [postSlug]
const path = postSlug.split('?')[0].split('#')[0]
if (path === '/' || path === '') {
slugList = ['/']
} else {
const hasTrailingSlash = path.endsWith('/')
const withSlash = hasTrailingSlash ? path : path + '/'
const withoutSlash = hasTrailingSlash ? path.slice(0, -1) : path
slugList = Array.from(new Set([withSlash, withoutSlash]))
}
}
try {