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

使用whatsapp-web.js时导出的Client对象导入后未更新求助

问题

使用whatsapp-web.js开发WhatsApp机器人时,想要在多个文件中复用Client实例,但导出后导入的文件只能拿到初始的空对象{}。此前未使用RemoteAuth时,全局对象更新的方式能正常工作,但改用RemoteAuth(在mongoose连接的异步回调里实例化Client)后就失效了。

导出代码

const { Client, RemoteAuth } = require('whatsapp-web.js');

var client = {}
// Require database
mongoose.connect(DATABASE_URL).then(async () => {
    const store = new MongoStore({ mongoose: mongoose });

    client = new Client({
        authStrategy: new RemoteAuth({
            store: store,
            backupSyncIntervalMs: 300000
        }),
        headless: false,
        puppeteer: {
            args: [
                '--no-sandbox',
                '--disable-setuid-sandbox',
                '--disable-dev-shm-usage',
                '--disable-accelerated-2d-canvas',
                '--no-first-run',
                '--no-zygote',
                '--disable-gpu'
            ],
        },
    });

    client.on('authenticated', async () => {
        console.log('Client is authenticated!');
    });
    client.on('qr', async qr => {
        qrcode.generate(qr, { small: true });
    });
    client.on('ready', async () => {
        console.log('Client is ready!');
    });

    client.on('remote_session_saved', () => {
        console.log('Client is saved!');
    });
    client.initialize();
});

exports.client = client

导入及使用代码

var client = require('../app').client;

//Funcion para que se envie correo de minimo de productos
async function correoAgotados(agotados) {
    console.log('inicia proceso de envio de correo')
    var mensaje = "Saludos desde " + agotados[0].planta + ", <br>";
    for (var i = 0; i < agotados.length; i++)
        mensaje = mensaje + "<p>El producto: " + agotados[i].producto + " ha llegado a su minimo.</p>" + "<p>Cantidad en Existencia: " + agotados[i].cantidad + " " + agotados[i].unidadCosteo + "</p><p>Minimo Registrado: " + agotados[i].min + " " + agotados[i].unidadCosteo + "</p> <br>"

    var mailOptions = {
        from: '--',
        to: '--',
        subject: 'Falta de Materiales',
        html: mensaje
    };
    try {
        var contacts = ['--']
        if (agotados[0].planta == 'Hadrok')
            contacts.push('--')
        mensaje = mensaje
        for (var i = 0; i < contacts.length; i++) {
            await client.sendMessage('521' + contacts[i] + '@c.us', mensaje.replace(/<br>|<p>/g, '\n').replace(/<\/p>/g, ''))
        }
    } catch {
        console.log('error de bot')
        console.log(client)
    }
}

解决方案

问题核心是变量引用的赋值逻辑:
你一开始把client赋值为空对象,exports.client = client导出的是这个空对象的引用。但在mongoose连接的异步回调里,client = new Client(...)是把变量指向了一个新对象,导出的引用不会自动更新到新对象上。之前不用RemoteAuth时是同步实例化,所以导出时已经是正确实例,异步逻辑打破了这个流程。

修复方法

方法一:导出Promise,等待Client实例化完成

把Client的创建过程包装成Promise,导入方通过等待Promise拿到就绪的实例:

const { Client, RemoteAuth } = require('whatsapp-web.js');

// 用Promise包裹Client实例化流程
const clientPromise = mongoose.connect(DATABASE_URL).then(async () => {
    const store = new MongoStore({ mongoose: mongoose });

    const client = new Client({
        authStrategy: new RemoteAuth({
            store: store,
            backupSyncIntervalMs: 300000
        }),
        headless: false,
        puppeteer: {
            args: [
                '--no-sandbox',
                '--disable-setuid-sandbox',
                '--disable-dev-shm-usage',
                '--disable-accelerated-2d-canvas',
                '--no-first-run',
                '--no-zygote',
                '--disable-gpu'
            ],
        },
    });

    // 绑定事件
    client.on('authenticated', async () => {
        console.log('Client is authenticated!');
    });
    client.on('qr', async qr => {
        qrcode.generate(qr, { small: true });
    });
    client.on('ready', async () => {
        console.log('Client is ready!');
    });

    client.on('remote_session_saved', () => {
        console.log('Client is saved!');
    });

    await client.initialize();
    return client;
});

exports.clientPromise = clientPromise;

导入代码修改:

const clientPromise = require('../app').clientPromise;

async function correoAgotados(agotados) {
    console.log('inicia proceso de envio de correo')
    var mensaje = "Saludos desde " + agotados[0].planta + ", <br>";
    for (var i = 0; i < agotados.length; i++)
        mensaje = mensaje + "<p>El producto: " + agotados[i].producto + " ha llegado a su minimo.</p>" + "<p>Cantidad en Existencia: " + agotados[i].cantidad + " " + agotados[i].unidadCosteo + "</p><p>Minimo Registrado: " + agotados[i].min + " " + agotados[i].unidadCosteo + "</p> <br>"

    var mailOptions = {
        from: '--',
        to: '--',
        subject: 'Falta de Materiales',
        html: mensaje
    };
    try {
        // 等待Client实例化完成
        const client = await clientPromise;
        var contacts = ['--']
        if (agotados[0].planta == 'Hadrok')
            contacts.push('--')
        for (var i = 0; i < contacts.length; i++) {
            await client.sendMessage('521' + contacts[i] + '@c.us', mensaje.replace(/<br>|<p>/g, '\n').replace(/<\/p>/g, ''))
        }
    } catch (err) {
        console.log('error de bot', err)
        console.log(err)
    }
}

方法二:用对象包裹Client,保持引用不变

把Client放在一个对象里,修改对象属性而非替换整个变量,保证导出的引用始终指向同一个对象:

const { Client, RemoteAuth } = require('whatsapp-web.js');

// 用对象包裹client,保持引用不变
const clientWrapper = { client: null };

mongoose.connect(DATABASE_URL).then(async () => {
    const store = new MongoStore({ mongoose: mongoose });

    clientWrapper.client = new Client({
        authStrategy: new RemoteAuth({
            store: store,
            backupSyncIntervalMs: 300000
        }),
        headless: false,
        puppeteer: {
            args: [
                '--no-sandbox',
                '--disable-setuid-sandbox',
                '--disable-dev-shm-usage',
                '--disable-accelerated-2d-canvas',
                '--no-first-run',
                '--no-zygote',
                '--disable-gpu'
            ],
        },
    });

    // 绑定事件
    clientWrapper.client.on('authenticated', async () => {
        console.log('Client is authenticated!');
    });
    clientWrapper.client.on('qr', async qr => {
        qrcode.generate(qr, { small: true });
    });
    clientWrapper.client.on('ready', async () => {
        console.log('Client is ready!');
    });

    clientWrapper.client.on('remote_session_saved', () => {
        console.log('Client is saved!');
    });

    clientWrapper.client.initialize();
});

exports.clientWrapper = clientWrapper;

导入代码修改:

const clientWrapper = require('../app').clientWrapper;

async function correoAgotados(agotados) {
    console.log('inicia proceso de envio de correo')
    var mensaje = "Saludos desde " + agotados[0].planta + ", <br>";
    for (var i = 0; i < agotados.length; i++)
        mensaje = mensaje + "<p>El producto: " + agotados[i].producto + " ha llegado a su minimo.</p>" + "<p>Cantidad en Existencia: " + agotados[i].cantidad + " " + agotados[i].unidadCosteo + "</p><p>Minimo Registrado: " + agotados[i].min + " " + agotados[i].unidadCosteo + "</p> <br>"

    var mailOptions = {
        from: '--',
        to: '--',
        subject: 'Falta de Materiales',
        html: mensaje
    };
    try {
        // 先判断Client是否初始化完成
        if (!clientWrapper.client) {
            console.log('Client还未初始化完成');
            return;
        }
        var contacts = ['--']
        if (agotados[0].planta == 'Hadrok')
            contacts.push('--')
        for (var i = 0; i < contacts.length; i++) {
            await clientWrapper.client.sendMessage('521' + contacts[i] + '@c.us', mensaje.replace(/<br>|<p>/g, '\n').replace(/<\/p>/g, ''))
        }
    } catch (err) {
        console.log('error de bot', err)
        console.log(err)
    }
}

注意事项

  • 方法一的Promise方案更可靠,能确保拿到的是已经初始化完成的Client实例;
  • 方法二需要自行处理Client未就绪的情况,比如监听ready事件后再执行业务逻辑,避免调用API时实例未初始化。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 15:42:02