Skip to main content
Glama
route.ts4.36 kB
import { NextRequest, NextResponse } from "next/server"; import OSS from "ali-oss"; import { z } from "zod"; // 验证请求参数的schema const uploadRequestSchema = z.object({ fileName: z.string(), fileType: z.string(), fileSize: z.number().positive(), assetType: z.string().optional(), }); // 验证回调参数的schema const callbackSchema = z.object({ assetId: z.string(), url: z.string().url(), size: z.number().positive(), mimeType: z.string(), }); // 阿里云OSS配置 const ossConfig = { region: process.env.ALIYUN_OSS_REGION || "oss-cn-hangzhou", accessKeyId: process.env.ALIYUN_ACCESS_KEY_ID!, accessKeySecret: process.env.ALIYUN_ACCESS_KEY_SECRET!, bucket: process.env.ALIYUN_OSS_BUCKET!, }; // 生成唯一的文件名 function generateFileName(originalName: string, assetType?: string): string { const timestamp = Date.now(); const random = Math.random().toString(36).substring(2, 15); const extension = originalName.split('.').pop(); const prefix = assetType ? `${assetType}/` : "uploads/"; return `${prefix}${timestamp}_${random}.${extension}`; } // POST方法:获取OSS临时上传凭证 export async function POST(request: NextRequest) { try { const body = await request.json(); const { fileName, fileType, fileSize, assetType } = uploadRequestSchema.parse(body); // 验证文件大小(限制为10MB) const maxSize = 10 * 1024 * 1024; // 10MB if (fileSize > maxSize) { return NextResponse.json( { error: "文件大小超过限制" }, { status: 400 } ); } // 验证文件类型 const allowedTypes = [ "image/jpeg", "image/png", "image/gif", "image/webp", "image/svg+xml", "application/pdf", "text/plain", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ]; if (!allowedTypes.includes(fileType)) { return NextResponse.json( { error: "不支持的文件类型" }, { status: 400 } ); } // 生成OSS文件名 const ossFileName = generateFileName(fileName, assetType); // 创建OSS客户端 const client = new OSS(ossConfig); // 生成临时上传URL(有效期15分钟) const url = await client.signatureUrl(ossFileName, { method: 'PUT', expires: 900, // 15分钟 'Content-Type': fileType, }); // 生成用于回调的assetId const assetId = `${Date.now()}_${Math.random().toString(36).substring(2, 15)}`; return NextResponse.json({ success: true, uploadUrl: url, assetId, ossFileName, expires: Date.now() + 900 * 1000, // 过期时间戳 }); } catch (error) { console.error("OSS上传凭证生成失败:", error); if (error instanceof z.ZodError) { return NextResponse.json( { error: "请求参数无效", details: error.errors }, { status: 400 } ); } return NextResponse.json( { error: "服务器内部错误" }, { status: 500 } ); } } // GET方法:处理上传完成后的回调 export async function GET(request: NextRequest) { try { const { searchParams } = new URL(request.url); const assetId = searchParams.get("assetId"); const url = searchParams.get("url"); const size = searchParams.get("size"); const mimeType = searchParams.get("mimeType"); // 验证回调参数 const callbackData = callbackSchema.parse({ assetId, url, size: size ? parseInt(size) : 0, mimeType, }); // 这里可以添加数据库记录逻辑 // 例如:将上传的文件信息保存到数据库 console.log("文件上传完成:", { assetId: callbackData.assetId, url: callbackData.url, size: callbackData.size, mimeType: callbackData.mimeType, }); return NextResponse.json({ success: true, message: "文件上传成功", assetId: callbackData.assetId, url: callbackData.url, }); } catch (error) { console.error("上传回调处理失败:", error); if (error instanceof z.ZodError) { return NextResponse.json( { error: "回调参数无效", details: error.errors }, { status: 400 } ); } return NextResponse.json( { error: "服务器内部错误" }, { status: 500 } ); } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/metacode0602/open-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server