Vercel 504 Gateway Timeout 解決方案|2025 超時問題完整排解

Vercel 504 Gateway Timeout 解決方案|2025 超時問題完整排解

部署到 Vercel 後,API 開始報 504 錯誤。

本機明明沒問題,為什麼上線就超時?

這是 Serverless 環境最常見的問題之一。

這篇文章教你如何診斷和解決 Vercel 超時問題。


理解 Vercel 超時限制

執行時間限制

方案 Serverless Functions Edge Functions
Hobby(免費) 10 秒 30 秒
Pro 60 秒 30 秒
Enterprise 900 秒 30 秒

為什麼會超時?

常見原因:

  1. 資料庫查詢太慢
  2. 外部 API 回應慢
  3. 複雜運算
  4. 冷啟動 + 慢操作
  5. 大檔案處理
  6. 無限迴圈

診斷超時原因

查看 Vercel Logs

  1. 進入 Vercel Dashboard
  2. 點擊專案
  3. 選擇 Deployments
  4. 點擊 Logs

查看錯誤訊息和執行時間。

加入效能監控

// app/api/slow/route.ts
export async function GET() {
  const startTime = Date.now();

  // 你的邏輯
  const step1 = Date.now();
  console.log('Step 1:', step1 - startTime, 'ms');

  await someOperation();
  const step2 = Date.now();
  console.log('Step 2:', step2 - step1, 'ms');

  await anotherOperation();
  const step3 = Date.now();
  console.log('Step 3:', step3 - step2, 'ms');

  console.log('Total:', Date.now() - startTime, 'ms');

  return Response.json({ success: true });
}

分析瓶頸

常見瓶頸:

  1. 資料庫連線建立 - 冷啟動時特別明顯
  2. 複雜查詢 - 沒有索引、大量資料
  3. 外部 API - 第三方服務回應慢
  4. 檔案處理 - 大圖片、PDF 生成

解決方案一:優化程式碼

優化資料庫查詢

// ❌ 不好:N+1 查詢
const users = await db.users.findMany();
for (const user of users) {
  const orders = await db.orders.findMany({ where: { userId: user.id } });
  // ...
}

// ✅ 好:使用 include/join
const users = await db.users.findMany({
  include: {
    orders: true,
  },
});

加入索引

-- 為常查詢的欄位加索引
CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_orders_created_at ON orders(created_at);

限制查詢結果

// ❌ 不好:查詢所有資料
const orders = await db.orders.findMany();

// ✅ 好:分頁和限制
const orders = await db.orders.findMany({
  take: 20,
  skip: (page - 1) * 20,
  orderBy: { createdAt: 'desc' },
});

快取查詢結果

import { unstable_cache } from 'next/cache';

const getCachedData = unstable_cache(
  async () => {
    // 慢查詢
    return await db.stats.aggregate();
  },
  ['stats'],
  { revalidate: 300 } // 5 分鐘快取
);

export async function GET() {
  const data = await getCachedData();
  return Response.json(data);
}

解決方案二:使用串流

什麼是串流?

串流可以在資料準備好時立即發送,而不是等全部完成。

好處:

  • 避免超時
  • 使用者體驗更好
  • 不需要等待

實作串流回應

// app/api/stream/route.ts
export async function GET() {
  const encoder = new TextEncoder();

  const stream = new ReadableStream({
    async start(controller) {
      // 發送多個資料塊
      for (let i = 0; i < 10; i++) {
        const data = await fetchChunk(i);
        controller.enqueue(
          encoder.encode(JSON.stringify(data) + '\n')
        );
      }
      controller.close();
    },
  });

  return new Response(stream, {
    headers: {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
    },
  });
}

AI 回應串流

// app/api/chat/route.ts
import { streamText } from 'ai';
import { openai } from '@ai-sdk/openai';

export async function POST(req: Request) {
  const { messages } = await req.json();

  const result = await streamText({
    model: openai('gpt-4-turbo'),
    messages,
  });

  // 使用串流回應,避免超時
  return result.toDataStreamResponse();
}

解決方案三:使用 Edge Functions

為什麼 Edge 更快?

  1. 冷啟動幾乎為零
  2. 全球分散執行
  3. 更長的超時時間(30 秒)

遷移到 Edge

// app/api/fast/route.ts
export const runtime = 'edge'; // 關鍵

export async function GET(request: Request) {
  // 快速操作
  return Response.json({ fast: true });
}

Edge 的限制

不支援:

  • 完整 Node.js API
  • 某些 npm 套件
  • 大量記憶體操作

適合:

  • 簡單 API 請求
  • 認證檢查
  • 代理請求

解決方案四:非同步處理

使用佇列

對於長時間任務,改用非同步處理:

// app/api/start-job/route.ts
import { Queue } from '@upstash/queue';

const queue = new Queue();

export async function POST(req: Request) {
  const { data } = await req.json();

  // 加入佇列,立即返回
  const jobId = await queue.push({
    type: 'process-data',
    data,
  });

  return Response.json({
    jobId,
    status: 'processing',
    checkUrl: `/api/job-status/${jobId}`,
  });
}
// app/api/job-status/[id]/route.ts
export async function GET(
  request: Request,
  { params }: { params: { id: string } }
) {
  const job = await getJobStatus(params.id);

  return Response.json({
    id: params.id,
    status: job.status,
    result: job.result,
  });
}

使用 Vercel Cron Jobs

// vercel.json
{
  "crons": [
    {
      "path": "/api/process-queue",
      "schedule": "* * * * *"
    }
  ]
}
// app/api/process-queue/route.ts
export async function GET() {
  // 每分鐘處理佇列中的任務
  const jobs = await queue.pop(10);

  for (const job of jobs) {
    await processJob(job);
  }

  return Response.json({ processed: jobs.length });
}

解決方案五:設定更長超時

Vercel Pro 方案

Pro 方案可以延長到 60 秒:

// app/api/slow/route.ts
export const maxDuration = 60; // 60 秒

export async function POST(req: Request) {
  // 長時間操作
  await longOperation();
  return Response.json({ success: true });
}

評估是否需要升級

免費方案夠用的情況:

  • 簡單 API
  • 快取良好
  • 優化過的查詢

需要 Pro 的情況:

  • AI 生成
  • 大量資料處理
  • 複雜報表

解決方案六:分割請求

大任務分成小步驟

// 前端
async function processLargeData(items: any[]) {
  const batchSize = 50;
  const results = [];

  for (let i = 0; i < items.length; i += batchSize) {
    const batch = items.slice(i, i + batchSize);
    const result = await fetch('/api/process', {
      method: 'POST',
      body: JSON.stringify({ batch }),
    });
    results.push(await result.json());

    // 更新進度
    updateProgress((i + batchSize) / items.length * 100);
  }

  return results;
}

使用 Pagination

// app/api/export/route.ts
export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const page = parseInt(searchParams.get('page') || '1');
  const limit = 100;

  const data = await db.records.findMany({
    skip: (page - 1) * limit,
    take: limit,
  });

  return Response.json({
    data,
    hasMore: data.length === limit,
    nextPage: page + 1,
  });
}

解決方案七:使用外部服務

長時間任務外包

對於真正需要長時間的任務,考慮使用:

服務 適合場景
AWS Lambda 15 分鐘以內
Google Cloud Run 更長時間
Modal AI/ML 任務
Replicate AI 模型推論
Trigger.dev 背景任務

整合範例

// app/api/process-video/route.ts
export async function POST(req: Request) {
  const { videoUrl } = await req.json();

  // 發送到外部服務處理
  const job = await fetch('https://api.modal.com/process', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.MODAL_API_KEY}`,
    },
    body: JSON.stringify({ videoUrl }),
  });

  const { jobId } = await job.json();

  return Response.json({
    jobId,
    status: 'processing',
  });
}

預防超時的最佳實踐

1. 設計時考慮超時

// 設定請求超時
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 8000);

try {
  const response = await fetch(url, {
    signal: controller.signal,
  });
  clearTimeout(timeout);
  return response;
} catch (error) {
  clearTimeout(timeout);
  if (error.name === 'AbortError') {
    // 處理超時
  }
  throw error;
}

2. 實作快取策略

import { kv } from '@vercel/kv';

export async function GET(request: Request) {
  const cacheKey = 'expensive-data';

  // 先檢查快取
  const cached = await kv.get(cacheKey);
  if (cached) {
    return Response.json(cached);
  }

  // 執行慢操作
  const data = await expensiveOperation();

  // 存入快取
  await kv.set(cacheKey, data, { ex: 300 });

  return Response.json(data);
}

3. 監控和告警

// 記錄慢請求
export async function GET(request: Request) {
  const startTime = Date.now();

  try {
    const result = await operation();
    const duration = Date.now() - startTime;

    // 記錄慢請求
    if (duration > 5000) {
      console.warn('Slow request:', {
        path: request.url,
        duration,
      });
      await sendAlert('Slow API detected');
    }

    return Response.json(result);
  } catch (error) {
    const duration = Date.now() - startTime;
    console.error('Request failed:', { duration, error });
    throw error;
  }
}

常見問題 FAQ

Q1:10 秒真的不夠用嗎?

對於優化過的程式碼,10 秒通常夠用。

如果不夠:

  1. 先優化程式碼
  2. 再考慮升級方案

Q2:Edge Functions 可以完全避免超時嗎?

不行。Edge Functions 有 30 秒限制,而且功能受限。

但對於簡單操作,可以大幅減少超時問題。

Q3:升級 Pro 後就不會超時嗎?

Pro 有 60 秒限制,比免費方案好很多。

但如果程式本身有問題(如無限迴圈),還是會超時。

Q4:如何處理圖片/檔案生成?

  1. 使用串流
  2. 使用外部服務(如 Cloudinary)
  3. 先上傳到 S3,再處理

Q5:資料庫連線慢怎麼辦?

  1. 使用連線池
  2. 選擇靠近 Vercel 區域的資料庫
  3. 使用 Prisma Accelerate 或 PlanetScale

Vercel 超時解決方案重點整理

問題類型 推薦解決方案
資料庫慢 優化查詢、加索引、快取
外部 API 慢 設定超時、快取、非同步
複雜運算 分批處理、外部服務
冷啟動 Edge Functions
需要更長時間 升級 Pro、佇列處理

Vercel 部署失敗?

Build Error、環境變數、自訂網域,我們幫你快速排除問題。

解決 Vercel 問題


延伸閱讀

分享文章:
V

VibeFix

專門解決 AI Vibe Coding 後的疑難雜症,讓你的專案順利上線。

這篇文章有幫到你嗎?

如果還有問題,讓我們直接幫你解決!

聯繫我們