fix: 修正Blog Live2D缺失资源状态码
This commit is contained in:
parent
453d95ef35
commit
2a30049600
@ -1,4 +1,8 @@
|
|||||||
import { BadRequestException, Injectable } from '@nestjs/common';
|
import {
|
||||||
|
BadRequestException,
|
||||||
|
Injectable,
|
||||||
|
NotFoundException,
|
||||||
|
} from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { MinioClientService } from './asset-minio.service';
|
import { MinioClientService } from './asset-minio.service';
|
||||||
import type {
|
import type {
|
||||||
@ -11,6 +15,24 @@ const DEFAULT_LIVE2D_BUCKET = 'kt-template-online';
|
|||||||
const DEFAULT_LIVE2D_PREFIX = 'blog/live2d/pio';
|
const DEFAULT_LIVE2D_PREFIX = 'blog/live2d/pio';
|
||||||
const MAX_DECODE_DEPTH = 6;
|
const MAX_DECODE_DEPTH = 6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects MinIO/S3 object-missing errors from `statObject` and `getObject`.
|
||||||
|
* @param error - Unknown failure thrown by the MinIO client while resolving a runtime object.
|
||||||
|
* @returns `true` when the failure means the requested object key does not exist.
|
||||||
|
*/
|
||||||
|
function isMinioObjectNotFound(error: unknown): boolean {
|
||||||
|
if (!error || typeof error !== 'object') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const candidate = error as { code?: unknown; message?: unknown };
|
||||||
|
return (
|
||||||
|
candidate.code === 'NotFound' ||
|
||||||
|
candidate.code === 'NoSuchKey' ||
|
||||||
|
candidate.message === 'Not Found'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BlogLive2DAssetService {
|
export class BlogLive2DAssetService {
|
||||||
/**
|
/**
|
||||||
@ -54,10 +76,17 @@ export class BlogLive2DAssetService {
|
|||||||
version: string,
|
version: string,
|
||||||
objectPath: BlogLive2DRuntimeAssetPath,
|
objectPath: BlogLive2DRuntimeAssetPath,
|
||||||
): Promise<BlogLive2DAssetResult> {
|
): Promise<BlogLive2DAssetResult> {
|
||||||
return this.minioClientService.getObject(
|
try {
|
||||||
this.resolveRuntimeObjectPath(version, objectPath),
|
return await this.minioClientService.getObject(
|
||||||
this.getBucketName(),
|
this.resolveRuntimeObjectPath(version, objectPath),
|
||||||
);
|
this.getBucketName(),
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
if (isMinioObjectNotFound(error)) {
|
||||||
|
throw new NotFoundException('Live2D runtime asset not found');
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -117,6 +117,28 @@ describe('BlogLive2DAssetService', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('maps missing MinIO runtime objects to HTTP 404', async () => {
|
||||||
|
const minio = createMinio();
|
||||||
|
minio.getObject.mockRejectedValueOnce(
|
||||||
|
Object.assign(new Error('Not Found'), { code: 'NotFound' }),
|
||||||
|
);
|
||||||
|
const service = new BlogLive2DAssetService(
|
||||||
|
minio as never,
|
||||||
|
createConfig() as never,
|
||||||
|
);
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
service.getRuntimeObject('v1', ['manifest.json']),
|
||||||
|
).rejects.toMatchObject({
|
||||||
|
status: HttpStatus.NOT_FOUND,
|
||||||
|
message: 'Live2D runtime asset not found',
|
||||||
|
});
|
||||||
|
expect(minio.getObject).toHaveBeenCalledWith(
|
||||||
|
'blog/live2d/pio/v1/manifest.json',
|
||||||
|
'kt-template-online',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('rejects runtime path traversal before touching MinIO', async () => {
|
it('rejects runtime path traversal before touching MinIO', async () => {
|
||||||
const minio = createMinio();
|
const minio = createMinio();
|
||||||
const service = new BlogLive2DAssetService(
|
const service = new BlogLive2DAssetService(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user