NextJS生产环境API连接被拒绝(增量静态再生调用问题)
Next.js生产模式下ISR校验接口连接失败问题
我配置了Node.js服务器(端口3001),在用户添加产品时发送POST请求到Next.js(端口3000)的/api/revalidate接口触发增量静态再生(ISR)。开发模式下两者交互正常,但构建Next.js应用并以生产模式启动后,出现连接拒绝错误。
相关代码
Next.js /api/revalidate 接口代码
async function handleRevalidate(req, res) { console.log("/api/revalidate received:", req.body); const event = req.body; if (event.model === "product") { const id = event.entry.id; await Promise.all([res.revalidate("/"), res.revalidate(`/products/${id}`)]); console.log("revalidated product", id); } res.status(204).end(); } export default handleRevalidate;
Node.js 调用接口的控制器代码
const addProduct = async (req, res) => { try { const query = mysql2.format("INSERT INTO products VALUES ?", [ [Object.values(req.body)], ]); const [resData, _] = await db.execute(query); console.log(resData); await axios.post("http://localhost:3000/api/revalidate", { model: "product", entry: { id: req.body.id, title: req.body.title, description: req.body.description, price: req.body.price, }, }); res.status(201).send("Product Added"); console.log(query); } catch (error) { console.log(error); } }; module.exports = addProduct
错误信息
AxiosError: connect ECONNREFUSED ::1:3000 at AxiosError.from (/Users/aiden/Documents/theavocado_backend/node_modules/axios/dist/node/axios.cjs:789:14) at RedirectableRequest.handleRequestError (/Users/aiden/Documents/theavocado_backend/node_modules/axios/dist/node/axios.cjs:2744:25) at RedirectableRequest.emit (node:events:513:28) at eventHandlers.<computed> (/Users/aiden/Documents/theavocado_backend/node_modules/follow-redirects/index.js:14:24) at ClientRequest.emit (node:events:513:28) at Socket.socketErrorListener (node:_http_client:490:9) at Socket.emit (node:events:513:28) at emitErrorNT (node:internal/streams/destroy:151:8) at emitErrorCloseNT (node:internal/streams/destroy:116:3) at process.processTicksAndRejections (node:internal/process/task_queues:82:21) { port: 3000, address: '::1', syscall: 'connect', code: 'ECONNREFUSED', errno: -61, config: { transitional: { silentJSONParsing: true, forcedJSONParsing: true, clarifyTimeoutError: false }, adapter: [ 'xhr', 'http' ], transformRequest: [ [Function: transformRequest] ], transformResponse: [ [Function: transformResponse] ], timeout: 0, xsrfCookieName: 'XSRF-TOKEN', xsrfHeaderName: 'X-XSRF-TOKEN', maxContentLength: -1, maxBodyLength: -1, env: { FormData: [Function], Blob: [class Blob] }, validateStatus: [Function: validateStatus], headers: AxiosHeaders { Accept: 'application/json, text/plain, */*', 'Content-Type': 'application/json', 'User-Agent': 'axios/1.2.2', 'Content-Length': '118', 'Accept-Encoding': 'gzip, compress, deflate, br' }, method: 'post', url: 'http://localhost:3000/api/revalidate', data: '{"model":"product","entry":{"id":87663301,"title":"KL Light","description":"Very energy efficient light.","price":12}}' }, request: <ref *1> Writable { _writableState: WritableState { objectMode: false, highWaterMark: 16384, finalCalled: false, needDrain: false, ending: false, ended: false, finished: false, destroyed: false, decodeStrings: true, defaultEncoding: 'utf8', length: 0, writing: false, corked: 0, sync: true, bufferProcessing: false, onwrite: [Function: bound onwrite], writecb: null, writelen: 0, afterWriteTickInfo: null, buffered: [], bufferedIndex: 0, allBuffers: true, allNoop: true, pendingcb: 0, constructed: true, prefinished: false, errorEmitted: false, emitClose: true, autoDestroy: true, errored: null, closed: false, closeEmitted: false, [Symbol(kOnFinished)]: [] }, _events: [Object: null prototype] { response: [Function: handleResponse], error: [Function: handleRequestError], socket: [Function: handleRequestSocket] }, _eventsCount: 3, _maxListeners: undefined, _options: { maxRedirects: 21, maxBodyLength: Infinity, protocol: 'http:', path: '/api/revalidate', method: 'POST', headers: [Object: null prototype], agents: [Object], auth: undefined, beforeRedirect: [Function: dispatchBeforeRedirect], beforeRedirects: [Object], hostname: 'localhost', port: '3000', agent: undefined, nativeProtocols: [Object], pathname: '/api/revalidate' }, _ended: false, _ending: true, _redirectCount: 0, _redirects: [], _requestBodyLength: 118, _requestBodyBuffers: [ [Object] ], _onNativeResponse: [Function (anonymous)], _currentRequest: ClientRequest { _events: [Object: null prototype], _eventsCount: 7, _maxListeners: undefined, outputData: [], outputSize: 0, writable: true, destroyed: false, _last: false, chunkedEncoding: false, shouldKeepAlive: true, maxRequestsOnConnectionReached: false, _defaultKeepAlive: true, useChunkedEncodingByDefault: true, sendDate: false, _removedConnection: false, _removedContLen: false, _removedTE: false, strictContentLength: false, _contentLength: '118', _hasBody: true, _trailer: '', finished: false, _headerSent: true, _closed: false, socket: [Socket], _header: 'POST /api/revalidate HTTP/1.1\r\n' + 'Accept: application/json, text/plain, */*\r\n' + 'Content-Type: application/json\r\n' + 'User-Agent: axios/1.2.2\r\n' + 'Content-Length: 118\r\n' + 'Accept-Encoding: gzip, compress, deflate, br\r\n' + 'Host: localhost:3000\r\n' + 'Connection: keep-alive\r\n' + '\r\n', _keepAliveTimeout: 0, _onPendingData: [Function: nop], agent: [Agent], socketPath: undefined, method: 'POST', maxHeaderSize: undefined, insecureHTTPParser: undefined, path: '/api/revalidate', _ended: false, res: null, aborted: false, timeoutCb: [Function: emitRequestTimeout], upgradeOrConnect: false, parser: null, maxHeadersCount: null, reusedSocket: false, host: 'localhost', protocol: 'http:', _redirectable: [Circular *1], [Symbol(kCapture)]: false, [Symbol(kBytesWritten)]: 0, [Symbol(kEndCalled)]: false, [Symbol(kNeedDrain)]: false, [Symbol(corked)]: 0, [Symbol(kOutHeaders)]: [Object: null prototype], [Symbol(errored)]: null, [Symbol(kUniqueHeaders)]: null }, _currentUrl: 'http://localhost:3000/api/revalidate', [Symbol(kCapture)]: false }, cause: Error: connect ECONNREFUSED ::1:3000 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1471:16) { errno: -61, code: 'ECONNREFUSED', syscall: 'connect', address: '::1', port: 3000 } }
解决方法
1. 调整Next.js生产服务监听地址
启动Next.js生产服务时,指定监听所有IPv4/IPv6地址:
next start -H 0.0.0.0 -p 3000
或者修改package.json的启动脚本:
"scripts": { "start": "next start -H 0.0.0.0 -p 3000" }
2. 修改Node.js请求URL为IPv4地址
将请求中的localhost替换为127.0.0.1,避免DNS解析到IPv6地址:
await axios.post("http://127.0.0.1:3000/api/revalidate", { model: "product", entry: { id: req.body.id, title: req.body.title, description: req.body.description, price: req.body.price, }, });
3. 确认Next.js服务正常启动
执行next start后,检查控制台输出是否包含类似内容,确认服务已在3000端口启动:
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
4. 检查端口占用情况
如果端口3000被其他进程占用,先停止占用进程或更换端口:
# macOS/Linux lsof -i :3000 # Windows netstat -ano | findstr :3000
内容的提问来源于stack exchange,提问作者Aidenhsy
相关产品推荐
相关产品推荐

