170 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 诊断预览图URL是否可访问
* GET /api/diagnose/preview-image?url={预览图URL}
*/
import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { HeadObjectCommand } from '@aws-sdk/client-s3';
import { s3Client, isS3PublicUrl } from '@/lib/s3';
import { rewriteStorageUrlForClient } from '@/lib/url-rewrite';
export async function GET(request: NextRequest) {
try {
const session = await getServerSession(authOptions);
if (!session) {
return NextResponse.json(
{ error: '未登录' },
{ status: 401 }
);
}
const url = request.nextUrl.searchParams.get('url');
if (!url) {
return NextResponse.json(
{ error: '缺少url参数' },
{ status: 400 }
);
}
const results: any = {
originalUrl: url,
checks: [],
};
// 1. 检查URL格式
let parsedUrl: URL;
try {
parsedUrl = new URL(url);
results.checks.push({
name: 'URL格式',
status: 'success',
message: 'URL格式正确',
details: {
protocol: parsedUrl.protocol,
hostname: parsedUrl.hostname,
pathname: parsedUrl.pathname,
}
});
} catch (error) {
results.checks.push({
name: 'URL格式',
status: 'error',
message: 'URL格式错误',
error: error instanceof Error ? error.message : String(error)
});
return NextResponse.json(results);
}
// 2. 检查URL重写后的地址
const rewrittenUrl = rewriteStorageUrlForClient(url, request);
results.rewrittenUrl = rewrittenUrl;
results.checks.push({
name: 'URL重写',
status: rewrittenUrl !== url ? 'success' : 'info',
message: rewrittenUrl !== url ? 'URL已重写' : 'URL未重写',
details: {
original: url,
rewritten: rewrittenUrl,
}
});
// 3. 检查是否为S3 URL
const isS3 = isS3PublicUrl(url);
results.isS3Url = isS3;
results.checks.push({
name: 'S3 URL检测',
status: isS3 ? 'success' : 'info',
message: isS3 ? '是S3公网URL' : '不是S3公网URL',
});
// 4. 如果是S3 URL,检查文件是否存在
if (isS3) {
try {
// 从URL提取key
const urlObj = new URL(url);
const key = urlObj.pathname.slice(1); // 移除开头的斜杠
const command = new HeadObjectCommand({
Bucket: process.env.S3_BUCKET!,
Key: key,
});
const response = await s3Client.send(command);
results.checks.push({
name: 'S3文件存在性',
status: 'success',
message: '文件存在于S3',
details: {
key: key,
contentLength: response.ContentLength,
contentType: response.ContentType,
lastModified: response.LastModified?.toISOString(),
}
});
} catch (error: any) {
if (error.name === 'NotFound' || error.$metadata?.httpStatusCode === 404) {
results.checks.push({
name: 'S3文件存在性',
status: 'error',
message: '文件不存在于S3',
error: '404 Not Found'
});
} else {
results.checks.push({
name: 'S3文件存在性',
status: 'error',
message: '检查S3文件时出错',
error: error.message || String(error)
});
}
}
}
// 5. 尝试通过HTTP访问(使用重写后的URL)
if (rewrittenUrl) {
try {
const response = await fetch(rewrittenUrl, {
method: 'HEAD',
signal: AbortSignal.timeout(5000), // 5秒超时
});
results.checks.push({
name: 'HTTP访问',
status: response.ok ? 'success' : 'error',
message: response.ok ? `HTTP访问成功 (${response.status})` : `HTTP访问失败 (${response.status})`,
details: {
status: response.status,
statusText: response.statusText,
contentType: response.headers.get('content-type'),
contentLength: response.headers.get('content-length'),
}
});
} catch (error: any) {
results.checks.push({
name: 'HTTP访问',
status: 'error',
message: 'HTTP访问失败',
error: error.message || String(error),
details: {
isTimeout: error.name === 'AbortError',
isNetworkError: error.message?.includes('fetch'),
}
});
}
}
return NextResponse.json(results);
} catch (error) {
console.error('[Diagnose Preview Image] Error:', error);
return NextResponse.json(
{
error: '诊断失败',
message: error instanceof Error ? error.message : String(error)
},
{ status: 500 }
);
}
}