Fix Vercel serverless deployment: optimize for fast loading

- Convert Express app to Vercel serverless function
- Add missing /api/files/public endpoint
- Optimize static file routing with proper caching
- Remove unnecessary dependencies for faster cold starts
- Add comprehensive debugging and error handling
- Improve API response times and user experience
This commit is contained in:
2025-08-21 13:25:57 +09:00
parent ce29d6bc3b
commit ec5da4db32
6 changed files with 162 additions and 154 deletions

View File

@@ -1,35 +1,33 @@
const express = require('express');
const cors = require('cors');
const path = require('path');
// Vercel Serverless 함수 핸들러
export default function handler(req, res) {
// CORS 헤더 설정
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
if (req.method === 'OPTIONS') {
res.status(200).end();
return;
}
const app = express();
const { url, method } = req;
// 헬스 체크
if (url === '/health' || url === '/api/health') {
res.json({
success: true,
message: 'Jaryo File Manager is running',
timestamp: new Date().toISOString(),
environment: process.env.NODE_ENV || 'production',
path: url
});
return;
}
// CORS 설정 - 모든 도메인 허용
app.use(cors({
origin: true,
credentials: true
}));
// JSON 파싱
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true, limit: '10mb' }));
// 정적 파일 서빙
app.use(express.static(path.join(__dirname, '..')));
// 헬스 체크
app.get('/health', (req, res) => {
res.json({
success: true,
message: 'Jaryo File Manager is running',
timestamp: new Date().toISOString(),
environment: process.env.NODE_ENV || 'development'
});
});
// 루트 경로
app.get('/', (req, res) => {
res.send(`
// 루트 경로
if (url === '/' || url === '/api') {
res.setHeader('Content-Type', 'text/html');
res.send(`
<!DOCTYPE html>
<html lang="ko">
<head>
@@ -37,80 +35,29 @@ app.get('/', (req, res) => {
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Jaryo File Manager</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
.container {
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #333;
text-align: center;
}
.status {
background: #e8f5e8;
border: 1px solid #4caf50;
padding: 15px;
border-radius: 5px;
margin: 20px 0;
}
.feature {
background: #f0f8ff;
border: 1px solid #2196f3;
padding: 15px;
border-radius: 5px;
margin: 10px 0;
}
.button {
background: #4caf50;
color: white;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
text-decoration: none;
display: inline-block;
margin: 5px;
}
.button:hover {
background: #45a049;
}
body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; background-color: #f5f5f5; }
.container { background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
h1 { color: #333; text-align: center; }
.status { background: #e8f5e8; border: 1px solid #4caf50; padding: 15px; border-radius: 5px; margin: 20px 0; }
.feature { background: #f0f8ff; border: 1px solid #2196f3; padding: 15px; border-radius: 5px; margin: 10px 0; }
.button { background: #4caf50; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; text-decoration: none; display: inline-block; margin: 5px; }
.button:hover { background: #45a049; }
</style>
</head>
<body>
<div class="container">
<h1>🚀 Jaryo File Manager</h1>
<div class="status">
<h3>✅ 배포 성공!</h3>
<p>Vercel에서 성공적으로 배포되었습니다.</p>
<p><strong>배포 시간:</strong> ${new Date().toLocaleString('ko-KR')}</p>
<p>Vercel Serverless에서 성공적으로 실행 중입니다.</p>
<p><strong>시간:</strong> ${new Date().toLocaleString('ko-KR')}</p>
</div>
<div class="feature">
<h3>📁 주요 기능</h3>
<ul>
<li>파일 업로드 및 관리</li>
<li>카테고리별 분류</li>
<li>파일 검색 및 다운로드</li>
<li>관리자 기능</li>
</ul>
</div>
<div class="feature">
<h3>🔧 API 엔드포인트</h3>
<p><a href="/health" class="button">헬스 체크</a></p>
<p><a href="/api/files" class="button">파일 목록 API</a></p>
<p><a href="/api/categories" class="button">카테고리 API</a></p>
<p><a href="/api/files/public" class="button">공개 파일 API</a></p>
</div>
<div class="feature">
<h3>📱 페이지</h3>
<p><a href="/index.html" class="button">메인 페이지</a></p>
@@ -119,37 +66,59 @@ app.get('/', (req, res) => {
</div>
</body>
</html>
`);
});
`);
return;
}
// API 라우트들
app.get('/api/files', (req, res) => {
res.json({
success: true,
data: [],
message: '파일 목록 API (데모 모드)'
});
});
// API 라우트들
if (url === '/api/files' || url === '/api/files/public') {
res.json({
success: true,
data: [
{
id: 1,
title: '샘플 문서',
description: '데모용 파일입니다',
category: '문서',
tags: ['샘플', '테스트'],
created_at: new Date().toISOString(),
file_url: '#'
},
{
id: 2,
title: '이미지 파일',
description: '예시 이미지',
category: '이미지',
tags: ['샘플'],
created_at: new Date().toISOString(),
file_url: '#'
}
],
message: url.includes('public') ? '공개 파일 목록' : '파일 목록 API (데모 모드)'
});
return;
}
app.get('/api/categories', (req, res) => {
res.json({
success: true,
data: [
{ id: 1, name: '문서', description: '문서 파일' },
{ id: 2, name: '이미지', description: '이미지 파일' },
{ id: 3, name: '기타', description: '기타 파일' }
],
message: '카테고리 목록'
});
});
if (url === '/api/categories') {
res.json({
success: true,
data: [
{ id: 1, name: '문서', description: '문서 파일' },
{ id: 2, name: '이미지', description: '이미지 파일' },
{ id: 3, name: '동영상', description: '동영상 파일' },
{ id: 4, name: '프레젠테이션', description: '프레젠테이션 파일' },
{ id: 5, name: '기타', description: '기타 파일' }
],
message: '카테고리 목록'
});
return;
}
// 404 핸들러
app.use((req, res) => {
// 404 핸들러
res.status(404).json({
success: false,
error: '요청한 리소스를 찾을 수 없습니다.',
path: req.path
path: url,
method: method
});
});
module.exports = app;
}