fix(worker-hall): 优化抢单大厅两级分类联动体验并支持分类图片浏览器长效缓存
This commit is contained in:
@@ -50,3 +50,17 @@ test('stored file URL drops signatures and refreshes them for responses', () =>
|
||||
'https://example.com/image.jpg',
|
||||
)
|
||||
})
|
||||
|
||||
test('public file scenes return stable unsigned URLs for browser caching', () => {
|
||||
const publicObjectKey = 'category_icon/2026/09/13/game-icon.png'
|
||||
const url = buildFileUrl(publicObjectKey, NOW_SECONDS)
|
||||
assert.equal(url, `/api/v1/files/object?key=${encodeURIComponent(publicObjectKey)}`)
|
||||
assert.equal(url.includes('expires='), false)
|
||||
assert.equal(url.includes('signature='), false)
|
||||
|
||||
const hallIconKey = 'hall_icon/2026/09/13/all-icon.png'
|
||||
const hallUrl = refreshStoredFileUrl(hallIconKey)
|
||||
assert.equal(hallUrl, `/api/v1/files/object?key=${encodeURIComponent(hallIconKey)}`)
|
||||
assert.equal(hallUrl.includes('expires='), false)
|
||||
assert.equal(hallUrl.includes('signature='), false)
|
||||
})
|
||||
|
||||
@@ -192,6 +192,9 @@ export function getMaxUploadSizeBytes() {
|
||||
|
||||
export function buildFileUrl(objectKey: string, nowSeconds = Math.floor(Date.now() / 1000)) {
|
||||
const normalizedKey = normalizeObjectKey(objectKey)
|
||||
if (isPublicObjectKey(normalizedKey)) {
|
||||
return buildUnsignedFileUrl(normalizedKey)
|
||||
}
|
||||
const expires = nowSeconds + FILE_URL_TTL_SECONDS
|
||||
const signature = createFileAccessSignature(normalizedKey, expires)
|
||||
return `${buildUnsignedFileUrl(normalizedKey)}&expires=${expires}&signature=${encodeURIComponent(signature)}`
|
||||
@@ -316,11 +319,17 @@ function extractObjectKeyFromFileUrl(value: string) {
|
||||
if (!value) return ''
|
||||
try {
|
||||
const parsed = new URL(value, 'http://localhost')
|
||||
if (parsed.pathname !== '/api/v1/files/object') return ''
|
||||
return normalizeObjectKey(parsed.searchParams.get('key'))
|
||||
if (parsed.pathname === '/api/v1/files/object') {
|
||||
return normalizeObjectKey(parsed.searchParams.get('key'))
|
||||
}
|
||||
} catch {
|
||||
return ''
|
||||
// ignore
|
||||
}
|
||||
const trimmed = value.trim()
|
||||
if (!trimmed.includes('://') && !trimmed.startsWith('/') && trimmed.includes('/')) {
|
||||
return normalizeObjectKey(trimmed)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
function normalizeContentType(mimeType: unknown, data: Buffer) {
|
||||
|
||||
@@ -41,6 +41,8 @@ export type StoredObject = {
|
||||
reader: Readable
|
||||
contentType: string
|
||||
size: number
|
||||
etag?: string | undefined
|
||||
lastModified?: Date | undefined
|
||||
}
|
||||
|
||||
export class ObjectStorage {
|
||||
@@ -114,6 +116,8 @@ export class ObjectStorage {
|
||||
reader,
|
||||
contentType: String(output.ContentType || 'application/octet-stream'),
|
||||
size: Number(output.ContentLength || 0),
|
||||
...(output.ETag ? { etag: String(output.ETag) } : {}),
|
||||
...(output.LastModified ? { lastModified: output.LastModified } : {}),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,6 +98,17 @@ export async function listWorkerHallOrders(query: JsonObject = {}, session: Work
|
||||
})
|
||||
}
|
||||
|
||||
export async function getWorkerHallCategories(session: WorkerSession) {
|
||||
requireActiveWorkerSession(session)
|
||||
const hallConfig = getWorkerHallConfig()
|
||||
const categories = (await listWorkCategories()).map(mapWorkCategory)
|
||||
return {
|
||||
categories,
|
||||
showSubcategories: hallConfig.showSubcategories,
|
||||
allIconUrl: hallConfig.allIconUrl ? refreshStoredFileUrl(hallConfig.allIconUrl) : null,
|
||||
}
|
||||
}
|
||||
|
||||
export async function getWorkerHallLeaderboard(session: WorkerSession, period: unknown = 'all') {
|
||||
requireActiveWorkerSession(session)
|
||||
const leaderboardPeriod = period === 'daily' ? 'daily' : 'all'
|
||||
|
||||
@@ -44,6 +44,7 @@ export {
|
||||
} from './worker-profile-service.js'
|
||||
|
||||
export {
|
||||
getWorkerHallCategories,
|
||||
getWorkerHallLeaderboard,
|
||||
listWorkerHallOrders,
|
||||
maskWorkerLeaderboardDisplayName,
|
||||
|
||||
Reference in New Issue
Block a user