From a87fe373ca7755861e1a3d949fb4030eaa481acb Mon Sep 17 00:00:00 2001 From: anghunk Date: Mon, 9 Feb 2026 17:28:33 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=94=B9=E8=BF=9B=E8=AF=84=E8=AE=BA?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E6=8E=A5=E5=8F=A3=E7=9A=84slug=E8=A7=84?= =?UTF-8?q?=E8=8C=83=E5=8C=96=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复当post_slug参数为根路径或包含查询参数/锚点时,slug列表生成逻辑不正确的问题。现在会先去除查询参数和锚点,然后正确处理根路径和带斜杠的变体。 新增单元测试验证各种slug格式的规范化行为,包括相对路径、完整URL和根路径。 --- cwd-api/src/api/public/getComments.spec.ts | 84 ++++++++++++++++++++++ cwd-api/src/api/public/getComments.ts | 10 ++- 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 cwd-api/src/api/public/getComments.spec.ts diff --git a/cwd-api/src/api/public/getComments.spec.ts b/cwd-api/src/api/public/getComments.spec.ts new file mode 100644 index 0000000..8a14ef6 --- /dev/null +++ b/cwd-api/src/api/public/getComments.spec.ts @@ -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('/') + }) +}) diff --git a/cwd-api/src/api/public/getComments.ts b/cwd-api/src/api/public/getComments.ts index 0e20199..452187f 100644 --- a/cwd-api/src/api/public/getComments.ts +++ b/cwd-api/src/api/public/getComments.ts @@ -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 {