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

Node.js中Firebase Admin SDK批量发消息遇ETIMEDOUT问题求助

问题:Node.js集成Firebase Admin SDK批量发送FCM消息时出现网络超时错误

错误信息

/Users/dbw/WebstormProjects/fcm_test/node_modules/firebase-admin/lib/utils/api-request.js:997
                throw new error_1.FirebaseAppError(error_1.AppErrorCodes.NETWORK_ERROR, `Error while making requests: ${error}`);
                ^

FirebaseAppError: Error while making requests: Error: connect ETIMEDOUT 2001:4860:4802:36::39:443
    at ClientHttp2Session.<anonymous> (/Users/dbw/WebstormProjects/fcm_test/node_modules/firebase-admin/lib/utils/api-request.js:997:23)
    at ClientHttp2Session.emit (node:events:513:28)
    at emitClose (node:internal/http2/core:1085:10)
    at process.processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errorInfo: {
    code: 'app/network-error',
    message: 'Error while making requests: Error: connect ETIMEDOUT 2001:4860:4802:36::39:443'
  },
  codePrefix: 'app'
}

问题描述

依据FCM官方文档在Node.js后端服务中集成Firebase Admin SDK发送消息,最初admin.messaging().send(message)步骤无响应并抛出上述网络超时错误。身处国内需代理访问国际网络,通过添加httpProxy解决了单条消息发送问题,但使用admin.messaging().sendEach([message])和admin.messaging().sendEachForMulticast(multiMessage)时,相同的ETIMEDOUT问题再次出现。而Java项目中无需代理即可正常发送消息。

请问Node.js与Java环境存在哪些差异?如何解决Node.js中批量消息发送的该问题?

相关代码

import * as admin from 'firebase-admin';
import { credential } from 'firebase-admin';
import { HttpsProxyAgent } from 'https-proxy-agent';
const credentialsPath = '/Users/dbw/Downloads/mars-messaging-test-firebase-adminsdk-i2mzh-362b2803d1.json';
const credentials = require(credentialsPath);
const httpAgent = new HttpsProxyAgent('http://127.0.0.1:7890/');
const app = admin.initializeApp({
    credential: credential.cert(credentials),
    httpAgent
});

const registrationToken =
    'my token';
const message = {
    "notification":{
        "title":"I am a title",
        "body":"I am a body"
    },
    token: registrationToken
};

const multiMessage = {
    data: {
        score: '850',
        time: '2:45'
    },
    tokens: [registrationToken]
};

const main = async () => {
    try {
        const result = await app.messaging().sendEachForMulticast(multiMessage);
        console.log('result: ' + result);
    } catch (err) {
        console.log('err: ' + err);
    }
};
解答

Node.js与Java环境的核心差异

  • HTTP协议版本差异:Node.js版Firebase Admin SDK默认使用HTTP/2发送批量消息,单条消息可能使用HTTP/1.1;而Java版SDK默认使用HTTP/1.1,部分代理工具对HTTP/2的兼容性较差,导致批量请求超时。
  • 代理配置覆盖范围差异:Java环境可能自动继承系统代理配置,且Firebase Java SDK内部对代理的处理逻辑能覆盖所有请求场景;Node.js版的httpAgent配置仅作用于单条请求的客户端,批量请求的HTTP/2客户端未继承该代理配置,直接发起无代理请求导致超时。
  • 连接池管理逻辑差异:Node.js的HTTP/2连接池管理与Java不同,批量请求时可能创建新的独立连接,未应用指定的代理设置,从而触发网络超时。

解决方法

1. 强制使用HTTP/1.1协议

初始化SDK时通过messagingOptions强制指定HTTP/1.1,规避HTTP/2的代理兼容问题:

const app = admin.initializeApp({
    credential: credential.cert(credentials),
    httpAgent,
    messagingOptions: {
        httpVersion: '1.1' // 强制使用HTTP/1.1协议
    }
});

2. 为批量请求手动配置代理客户端

创建自定义HTTP客户端并替换messaging模块的默认客户端,确保批量请求使用代理:

import * as admin from 'firebase-admin';
import { credential } from 'firebase-admin';
import { HttpsProxyAgent } from 'https-proxy-agent';
import * as http from 'http';
import * as https from 'https';

const credentialsPath = '/Users/dbw/Downloads/mars-messaging-test-firebase-adminsdk-i2mzh-362b2803d1.json';
const credentials = require(credentialsPath);
const proxyAgent = new HttpsProxyAgent('http://127.0.0.1:7890/');

// 创建带代理的自定义HTTP客户端
const customHttpClient = new admin.httpClient.HttpClient({
    httpAgent: new http.Agent({ agent: proxyAgent }),
    httpsAgent: new https.Agent({ agent: proxyAgent })
});

const app = admin.initializeApp({
    credential: credential.cert(credentials),
    httpAgent: proxyAgent
});

// 替换messaging模块的默认HTTP客户端
app.messaging()._httpClient = customHttpClient;

3. 优化代理的HTTP/2支持

若需保留HTTP/2,检查代理工具(如Clash、V2Ray)是否开启HTTP/2支持,或切换至对HTTP/2兼容性更好的代理服务。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 01:23:19