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

如何在自建服务器的Next.js应用中每小时运行定时任务并共享环境变量?

解决方案:Next.js 集成定时任务同步 API 数据

方案一:使用 concurrently 并行启动服务与定时脚本

这是最简洁的实现方式,无需修改 Next.js 核心配置,直接通过并行命令启动两个进程。

步骤1:安装依赖

npm install concurrently node-schedule --save-dev
  • concurrently:用于同时运行多个命令
  • node-schedule:支持 cron 表达式的灵活定时任务调度(比setInterval更适合复杂时间规则)

步骤2:编写定时同步脚本

在项目根目录创建scripts/fetch-app-info.js:

const fs = require('fs');
const path = require('path');
const schedule = require('node-schedule');
const fetch = require('node-fetch');

// 启动时先执行一次,确保初始化就有最新数据
fetchAppInfo();

// 每小时整点执行(cron表达式:0 * * * *)
schedule.scheduleJob('0 * * * *', fetchAppInfo);

async function fetchAppInfo() {
  try {
    // 从环境变量获取API地址
    const apiUrl = process.env.NEXT_PUBLIC_APP_INFO_API;
    if (!apiUrl) throw new Error('未配置APP_INFO_API环境变量');

    const res = await fetch(apiUrl);
    if (!res.ok) throw new Error(`API请求失败:${res.status}`);

    const data = await res.json();
    // 将数据写入public目录,方便SSR读取
    const outputPath = path.join(process.cwd(), 'public/app-info.json');
    fs.writeFileSync(outputPath, JSON.stringify(data, null, 2));

    console.log(`[${new Date().toISOString()}] 成功更新app-info数据`);
  } catch (err) {
    console.error(`[${new Date().toISOString()}] 更新app-info失败:`, err.message);
  }
}

若项目未安装node-fetch,需执行npm install node-fetch

步骤3:修改package.json启动命令

替换原有start和dev脚本:

{
  "scripts": {
    "dev": "concurrently \"next dev\" \"node scripts/fetch-app-info.js\"",
    "build": "next build",
    "start": "concurrently \"next start\" \"node scripts/fetch-app-info.js\""
  }
}

现在执行npm start或npm run dev时,会同时启动 Next.js 服务和定时同步脚本。


方案二:集成到自定义Next.js服务器

如果希望更一体化,可将定时任务嵌入 Next.js 自定义服务器中,无需额外进程。

步骤1:创建自定义服务器文件

在项目根目录创建server.js:

const { createServer } = require('http');
const { parse } = require('url');
const next = require('next');
const schedule = require('node-schedule');
const fs = require('fs');
const path = require('path');
const fetch = require('node-fetch');

const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();

// 启动定时任务
fetchAppInfo();
schedule.scheduleJob('0 * * * *', fetchAppInfo);

async function fetchAppInfo() {
  try {
    const apiUrl = process.env.NEXT_PUBLIC_APP_INFO_API;
    if (!apiUrl) throw new Error('未配置APP_INFO_API环境变量');

    const res = await fetch(apiUrl);
    if (!res.ok) throw new Error(`API请求失败:${res.status}`);

    const data = await res.json();
    const outputPath = path.join(process.cwd(), 'public/app-info.json');
    fs.writeFileSync(outputPath, JSON.stringify(data, null, 2));

    console.log(`[${new Date().toISOString()}] 成功更新app-info数据`);
  } catch (err) {
    console.error(`[${new Date().toISOString()}] 更新app-info失败:`, err.message);
  }
}

app.prepare().then(() => {
  createServer((req, res) => {
    const parsedUrl = parse(req.url, true);
    handle(req, res, parsedUrl);
  }).listen(process.env.PORT || 3000, (err) => {
    if (err) throw err;
    console.log(`> Ready on http://localhost:${process.env.PORT || 3000}`);
  });
});

步骤2:修改package.json启动命令

{
  "scripts": {
    "dev": "node server.js",
    "build": "next build",
    "start": "NODE_ENV=production node server.js"
  }
}

关键注意事项

  1. 环境变量访问:两种方案中,定时脚本都能直接读取 Next.js 的环境变量(同一shell环境下启动),.env.local等配置文件的变量会自动加载。
  2. SSR读取数据:在页面的getStaticProps或getServerSideProps中读取生成的JSON文件:
    import fs from 'fs';
    import path from 'path';
    
    export async function getStaticProps() {
      const filePath = path.join(process.cwd(), 'public/app-info.json');
      const appInfo = JSON.parse(fs.readFileSync(filePath, 'utf8'));
    
      return {
        props: { appInfo },
        revalidate: 0 // 无需静态刷新,依赖定时任务更新文件
      };
    }
    
  3. 错误处理:定时任务必须添加try-catch,避免单次API请求失败导致脚本崩溃,同时记录日志便于排查。
  4. 文件权限:确保Node.js进程有写入public目录的权限,避免写入失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 18:05:38