You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用EventSource对接Vercel无服务器函数时出现客户端504网关超时

Vercel无服务器函数上EventSource间歇性504网关超时问题解决

本地运行EventSource连接Next.js API路由(模拟MongoDB变更流推送)完全正常,但部署到Vercel后,连接间歇性返回504网关超时,即便已配置超时参数且客户端连接清理逻辑正确,问题仍存在。

服务端代码

import { NextApiRequest, NextApiResponse } from "next";

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  res.setHeader("Content-Type", "text/event-stream");
  res.setHeader("Cache-Control", "no-cache");
  res.setHeader("Connection", "keep-alive");
  res.writeHead(200);
  res.flushHeaders();

  let intervalId: NodeJS.Timeout;

  try {
    console.log("Change stream initialized");

    intervalId = setInterval(() => {
      const simulatedData = {
        timestamp: new Date().toISOString(),
        message: "This is a simulated message",
      };
      res.write(`data: ${JSON.stringify(simulatedData)}\n\n`);
      res.flush();
    }, 10000);

    req.on("close", () => {
      console.log("Client disconnected");
      clearInterval(intervalId);
      res.end();
    });
  } catch (error) {
    console.error("Error initializing change stream:", error);
    res.status(500).end();
  }
}

客户端代码

import { useEffect } from "react";

function MyComponent() {
  useEffect(() => {
    const eventSource = new EventSource(`/api/getdata`);

    eventSource.onmessage = (event) => {
      const data = JSON.parse(event.data);
      console.log('Received update:', data);
    };

    eventSource.onerror = (error) => {
      console.error('EventSource error:', error);
      eventSource.close();
    };

    return () => {
      eventSource.close();
      console.log('EventSource closed');
    };
  }, []);

  return <div>Listening for updates...</div>;
}

问题根源

Vercel普通无服务器函数(Serverless Functions)有最大执行时间限制(上限10秒),你的代码设置每10秒发送一次数据,函数执行时长会超过这个限制,导致Vercel主动终止连接,返回504超时。另外,普通无服务器函数是为短生命周期请求设计的,不支持长连接场景(如EventSource)。

解决方案

1. 切换到Vercel Edge Functions(推荐)

Edge Functions运行在边缘节点,支持长连接,无严格执行时间限制(只要连接活跃)。修改API路由配置:

  • 若使用Pages Router,在pages/api的函数文件中添加运行时配置:
export const config = {
  runtime: "edge",
};
  • 调整服务端代码适配Edge Functions(改用流式响应):
import { NextRequest, NextResponse } from "next/server";

export const config = {
  runtime: "edge",
};

export default async function handler(req: NextRequest) {
  const stream = new ReadableStream({
    start(controller) {
      const intervalId = setInterval(() => {
        const simulatedData = {
          timestamp: new Date().toISOString(),
          message: "This is a simulated message",
        };
        controller.enqueue(`data: ${JSON.stringify(simulatedData)}\n\n`);
      }, 10000);

      // 监听客户端断开事件,清理资源
      req.signal.addEventListener("abort", () => {
        clearInterval(intervalId);
        controller.close();
      });
    },
  });

  return new NextResponse(stream, {
    headers: {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache",
      Connection: "keep-alive",
    },
  });
}

2. 临时缓解:缩短数据发送间隔

如果暂时无法切换到Edge Functions,可将数据发送间隔缩短至10秒以内(如5秒),确保函数在Vercel超时限制内完成执行。但这只是临时方案,无法解决长连接的根本问题。

3. 第三方实时服务替代

若Edge Functions仍不满足需求,可使用Pusher、Supabase Realtime等第三方服务处理MongoDB变更流推送,无需自行维护长连接。

验证步骤

  • 部署Edge Functions后,查看Vercel控制台函数日志,确认连接保持活跃且无超时终止
  • 保留客户端原有EventSource逻辑,确保组件卸载时正确关闭连接

内容的提问来源于stack exchange,提问作者Devesh Maurya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 14:56:06