将Node.js Express后端部署到Vercel时遇404/500错误求助
Node.js Express部署Vercel遇404/500错误排查与修复
尝试将Node.js Express后端部署至Vercel平台时,持续出现404或500错误。项目根目录下有handlers文件夹,内部包含多个路由文件夹及index.js文件,该文件汇总所有路由逻辑并传递给根目录的index.js。以下是项目代码示例、当前配置及错误情况:
代码示例
handler/*.js 示例
const { exec } = require("child_process"); const { promisify } = require("util"); /** * @param {*} event * @param {*} models * @returns */ module.exports.handler = async function (event, models) { const execPromise = promisify(exec); const pythonReturn = await execPromise("python3 app.py"); const result = JSON.parse(pythonReturn.stdout) return { statusCode: 200, body: JSON.stringify(result), }; }; module.exports.path = "/getSurebets"; module.exports.method = "GET";
server.js
'use strict' const express = require('express') const bodyParser = require('body-parser') const cors = require('cors') const app = express() const router = express.Router() const aliveTime = new Date().getTime() const PORT = process.env.PORT || 3002; const Handler = require("./index") router.use(cors()) router.use(bodyParser.json()) router.use(bodyParser.urlencoded({ extended: true })) router.get('/', (req, res) => { req.json({ aliveTime }) }) router.use(async function(req, res){ const event = { "resource": req.path, "path": req.path, "httpMethod": req.method, "headers": req.headers, "queryStringParameters": req.query, "pathParameters": req.params, "stageVariables": null, "body": JSON.stringify(req.body), "isBase64Encoded": false, "requestContext": { "authorizer": {} } } try{ const response = await Handler.handler(event) res .set(response.headers) .status(response.statusCode) const data = response.body if(req.path.indexOf("render") < 0){ res.send(JSON.parse(data)) }else{ res.send(data) } }catch(e){ console.error(e) res.status(500).send(e) } }) app.use('/v1/', router) app.listen(PORT) console.log(`Listen on http://0.0.0.0:${PORT}`) module.exports = app
根目录 index.js
const fns = require("./handlers") const cors = require('./lib/cors') const models = require("./models"); const extractPathValues = (pathExpression, httpPath) => { const pathExpressionPattern = pathExpression.replace(/{[\w]+}|:[\w]+/g, '([^/]+)') const pathValueRegex = new RegExp(`^${pathExpressionPattern}$`) const pathValues = pathValueRegex.exec(httpPath) return pathValues && pathValues.length > 0 ? pathValues.slice(1) : null } const extractPathNames = (pathExpression) => { const pathExpressionPattern = pathExpression?.replace(/{[\w.]+}|:[\w.]+/g, '[:{]([\\w]+)}?'); const pathNameRegex = new RegExp(`^${pathExpressionPattern}$`) const pathNames = pathNameRegex.exec(pathExpression) return pathNames && pathNames.length > 0 ? pathNames.slice(1) : null } const getRouterHandler = (event) => { const routesByMethod = fns.filter(r => r.method === event.httpMethod) for(const route of routesByMethod) { const pathPartNames = extractPathNames(route.path) const pathValues = extractPathValues(route.path, event.path) if (pathValues && pathPartNames) { const params = {} let keyIndex = 0; for(const key of pathPartNames) { params[ key ] = pathValues[ keyIndex ] keyIndex++; } return {route, params} } } } const getHandler = async (event) => { return getRouterHandler(event) } exports.handler = async (event, context) => { if(event.Records) return tRender(event, context, models) if(process.env.NODE_ENV!=='test') console.log(event) const HANDLER = await getHandler(event) if(!HANDLER) return { statusCode: 404, body: JSON.stringify({ message: 'Not Found' }) } const { route, params } = HANDLER if(!event.pathParameters || !Object.keys(event.pathParameters).length) { event.pathParameters = params } if((process.env.NODE_ENV || '').trim() !== 'test') console.debug({ event }) const response = cors( await route.handler(event, models, context).catch(err => { console.error(err) if(!err.statusCode || !err.body ) { return Promise.reject(err) } return Promise.resolve(err) }) ) return response }
当前 vercel.config
{ "version": 2, "name": "omnes-api", "builds": [ { "src": "index.js", "use": "@vercel/node" } ], "routes": [ { "src": "handlers/index.js", "dest": "index.js" } ] }
错误情况

修复方案
1. 修正Vercel路由配置
当前路由规则仅匹配handlers/index.js路径,无法转发所有API请求。修改为匹配所有路径并指向根目录处理函数:
{ "version": 2, "name": "omnes-api", "builds": [ { "src": "index.js", "use": "@vercel/node" } ], "routes": [ { "src": "/(.*)", "dest": "/index.js" } ] }
2. 适配Express路径前缀
由于Express中使用了/v1/前缀,需在路由匹配逻辑中去除前缀,确保与handler中定义的路径匹配:
const getRouterHandler = (event) => { // 去除/v1/前缀,匹配handler中定义的path const strippedPath = event.path.replace(/^\/v1/, ''); const routesByMethod = fns.filter(r => r.method === event.httpMethod) for(const route of routesByMethod) { const pathPartNames = extractPathNames(route.path) const pathValues = extractPathValues(route.path, strippedPath) if (pathValues && pathPartNames) { const params = {} let keyIndex = 0; for(const key of pathPartNames) { params[ key ] = pathValues[ keyIndex ] keyIndex++; } return {route, params} } } }
3. 解决Python运行环境问题(500错误可能原因)
Vercel Node环境默认无Python,需添加Python构建支持或替换为Node实现:
{ "version": 2, "name": "omnes-api", "builds": [ { "src": "index.js", "use": "@vercel/node" }, { "src": "app.py", "use": "@vercel/python" } ], "routes": [ { "src": "/(.*)", "dest": "/index.js" } ] }
4. 本地验证
部署前用Vercel CLI测试:
vercel dev
访问http://localhost:3000/v1/getSurebets确认响应正常后再部署。
内容的提问来源于stack exchange,提问作者Daniel Alves
相关产品推荐
相关产品推荐

