首页 > 解决方案 > Node.js 网络模块,从回调函数中获取数据

问题描述

所以我尝试自己解决它并搜索了很多,但我无法真正解决问题,尽管我认为它不应该那么困难。所以我正在做(或试图做)的是,我建立一个到服务器的简单 telnet 连接并模拟 SMTP 会话的开始以验证是否存在电子邮件(如果这给我正确的结果是另一个问题)

我这样做的代码如下所示:

const net = require('net');

async function TCPConnection(smtpServer, emailDomain, senderEmail) {

    const client = new net.Socket();
    client.setEncoding("utf-8");
    let completeData = '';

    client.connect({port: 25, host: smtpServer}, () => {
        console.log("TCP Connection established with the Server.");
    })

    client.write("ehlo " + emailDomain + "\r\n");
    client.write("mail from:<" + senderEmail + ">\r\n");
    client.write("rcpt to:<" + senderEmail + ">\r\n");


    client.on('data', function (data) {
        console.log(data);
    });

    function dataReceived(data){
        completeData += data;
    }

    client.on('end', function () {
        console.log('Requested an end to the TCP connection');
    });
}

TCPConnection('aspmx.l.google.com', 'mailtrap.io', 'new-recipient@mailtrap.io');

服务器记录到控制台的响应如下所示:

TCP Connection established with the Server.
220 mx.google.com ESMTP m17si1129948edf.309 - gsmtp

250-mx.google.com at your service, [217.84.87.66]
250-SIZE 157286400
250-8BITMIME
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-CHUNKING
250 SMTPUTF8

250 2.1.0 OK m17si1129948edf.309 - gsmtp

550-5.1.1 The email account that you tried to reach does not exist. Please try
550-5.1.1 double-checking the recipient's email address for typos or
550-5.1.1 unnecessary spaces. Learn more at
550 5.1.1  https://support.google.com/mail/?p=NoSuchUser m17si1129948edf.309 - gsmtp

所以我想要实现的是从回调或 TCPConnection 函数中获取完整的数据(现在记录到控制台)。例如,使用“return completeData;” 在 TCPConnection 函数的末尾。

我想这样做的原因是,这个函数 (TCPConnection) 是通过 HTTP 请求调用的。我想把这个结果发回给客户。完整的功能可能看起来像这样(但显然到目前为止还没有工作):

app.post('/tcpConnection', (req, res) => {

    let smtpServer = req.body.smptServer;
    let domain = req.body.domain;
    let senderEmail = req.body.senderEmail;

    async function sendResponse(){
        let response = await TCPConnection(smtpServer,domain,senderEmail);
        await res.status(200).json(result);
    }

})

我阅读了解决方案,这可能是在“结束”事件发出后对我的数据做我想做的事情。但我的问题是,在我的三个“写命令”之后,服务器并没有立即结束连接。如果我写这个:

client.write("ehlo " + emailDomain + "\r\n");
client.write("mail from:<" + senderEmail + ">\r\n");
client.write("rcpt to:<" + senderEmail + ">\r\n");
client.end();

它在第二个和第三个命令得到响应之前结束连接。我试图用“await client.write ...”来“等待”响应,但这显然是行不通的,因为不确定是什么原因。

我希望你能大致了解我正在努力完成的工作,如果你不问的话。谢谢!

标签: javascriptnode.jsasynchronouscallback

解决方案


所以我想我自己已经完成了,或者至少得到了一个在大多数情况下都可以正常工作的解决方案。我正在做的是在第三个写命令的回调中结束套接字,如下所示:

client.write("rcpt to:<" + senderEmail + ">\r\n","utf-8",()=>{
            console.log("third command written");
            client.end();
        });

通过这样做,服务器“应该有足够的时间”来回答所有命令。

较早的解决方案是计算“数据”事件的回调函数中的响应数,如下所示:

client.on('data', function (data) {
        counterResponses++;
        console.log("Response Nr: " + counterResponses + '\r\n' + data);
        completeData.push(data);

        if (counterResponses === 4){
            console.log("4 responses received end connection");
            client.end();
        }
    });

因为我想在收到对我的命令的 4 个响应后结束套接字,所以我使用了一个 if 语句来检查响应的数量。但问题是,有时多个响应可能会作为一个响应发送。例如,响应可能如下所示:

Response Nr: 1
220 mtaproxy104.free.mail.ir2.yahoo.com ESMTP ready

Response Nr: 2
250-mtaproxy104.free.mail.ir2.yahoo.com
250-PIPELINING
250-SIZE 41943040
250-8BITMIME
250 STARTTLS

但也像这样:

Response Nr: 1
220 mtaproxy104.free.mail.ir2.yahoo.com ESMTP ready
250-mtaproxy104.free.mail.ir2.yahoo.com
250-PIPELINING
250-SIZE 41943040
250-8BITMIME
250 STARTTLS

所以 2 个响应作为一个发送。这使得很难评估我是否得到了我需要得到的所有回复。这就是为什么我只是在最后一个写命令之后结束套接字。

然后在 client.on('end') 函数中,我将 completeData 发送回客户端。

client.on('end', function () {
        console.log('Requested an end to the TCP connection');
        console.log(completeData);

        res.status(200).json(completeData);
    });

唯一仍然困扰我的是我的数组(我用每个发出的“数据”事件推送数据)的长度是可变的。如果找到电子邮件,这将使验证变得有点困难。但是由于这应该始终是最后一个响应,所以如果我只是测试数组的最后一个条目是否包含状态码“250”或“550”,它应该在大多数情况下工作。

我希望这至少对某人有所帮助。让我知道它是否对您有所帮助,或者您对此有任何疑问。也仍然开放以获得更好的解决方案,因为我相信有更好的方法来做到这一点。


推荐阅读