Node.js 如何使用NodeJ高效地将请求转发到多个端点?

Node.js 如何使用NodeJ高效地将请求转发到多个端点?,node.js,rest,Node.js,Rest,我构建了一个nodejs服务器作为适配器服务器,它在接收到包含一些数据的post请求时,从请求体中提取数据,然后将其转发给其他几个外部服务器。最后,我的服务器将发送一个由每个外部服务器的响应组成的响应(成功/失败) 如果只有一个端点要转发,那么它看起来相当简单。但是,当我必须转发到多个服务器时,我必须依赖于Promise.All()之类的东西,它具有快速失败的行为。这意味着,如果一个承诺被拒绝(外部服务器关闭),所有其他承诺也将立即被拒绝,其余的服务器将不会接收我的数据。听起来你在试图设计反向代

我构建了一个nodejs服务器作为适配器服务器,它在接收到包含一些数据的post请求时,从请求体中提取数据,然后将其转发给其他几个外部服务器。最后,我的服务器将发送一个由每个外部服务器的响应组成的响应(成功/失败)


如果只有一个端点要转发,那么它看起来相当简单。但是,当我必须转发到多个服务器时,我必须依赖于Promise.All()之类的东西,它具有快速失败的行为。这意味着,如果一个承诺被拒绝(外部服务器关闭),所有其他承诺也将立即被拒绝,其余的服务器将不会接收我的数据。

听起来你在试图设计反向代理。如果您正在努力让自定义代码正常工作,那么有一个非常健壮的免费npm库

我建议使用节点http代理

我已经发布了下面的链接,这将直接引导您进入“修改响应”,因为您在问题中提到了API格式的修改。但一定要阅读整个页面

注意:这个库也很好,因为它可以支持SSL,以及本地主机(同一台机器上的服务器)和其他机器上的服务器(远程)的代理

它拒绝的理由是第一个拒绝的承诺

要解决此问题,您需要
catch()
处理您发出的每个请求。 e、 g

Promise.all([
请求(“”).catch(err=>/*…错误处理*/),
请求(“”).catch(err=>/*…错误处理*/),
请求(“”).catch(错误=>/*…错误处理*/)
])
。然后(([result1,result2,result3])=>{
如果(result1.err){}
如果(result2.err){}
如果(result3.err){}
})

可能是,这不是确切的解决方案。但是,我发布的内容可能是解决您的问题

几天前我遇到了同样的问题,因为我想实现API版本控制。这是我实现的解决方案,请看一看

让我解释一下这个图表

图中是服务器的初始配置,与我们一样。这里的所有api请求都将传递到发布目录中的“index.js”文件

index.js(在发布目录中)

helper.js的代码片段

//requiring path and fs modules
const path = require('path');
const fs = require('fs');

module.exports = {
    getFiles: (presentDirectory, directoryName) => {

        return new Promise((resolve, reject) => {
            //joining path of directory 
            const directoryPath = path.join(presentDirectory, directoryName);
            //passsing directoryPath and callback function

            fs.readdir(directoryPath, function (err, files) {

                // console.log(files);

                //handling error
                if (err) {
                    console.log('Unable to scan directory: ' + err);
                    reject(err)
                }
                //listing all files using forEach
                // files.forEach(function (file) {
                //     // Do whatever you want to do with the file
                //     console.log(file); 
                // });
                resolve(files)
            });
        })


    }
}
现在,从这个索引文件映射每个版本文件夹中的所有index.js

下面是v1或v2中“index.js”的代码

const express = require('express');
const mongoose = require('mongoose');
const fid = require('../../core/file.helper');
const dbconf = require('./config/datastore');
const router = express.Router();

// const connection_string = `mongodb+srv://${dbconf.atlas.username}:${dbconf.atlas.password}@${dbconf.atlas.host}/${dbconf.atlas.database}`;
const connection_string = `mongodb://${dbconf.default.username}:${dbconf.default.password}@${dbconf.default.host}:${dbconf.default.port}/${dbconf.default.database}`;

mongoose.connect(connection_string,{
    useCreateIndex: true,    
    useNewUrlParser:true
}).then(status => {

    console.log(`Database connected to mongodb://${dbconf.atlas.username}@${dbconf.atlas.host}/${dbconf.atlas.database}`);

    fid.getFiles(__dirname,'./endpoints').then(files => {

        files.forEach(file => {
            file = file.replace(/.js/g,''); 
            router.use(`/${file}`,require(`./endpoints/${file}`))
        });

    })

}).catch(err => {
    console.log(`Error connecting database ${err}`);
})

module.exports = router
在每个版本中,index.js In version文件夹实际上映射到endpoints文件夹中的每个端点

其中一个端点的代码如下所示

const express = require('express');
const router = express.Router();

const userCtrl = require('../controllers/users');


router.post('/signup', userCtrl.signup);
router.post('/login', userCtrl.login);

module.exports = router;
在这个文件中,实际上我们正在将端点连接到它的控制器。

var config={'targets':
var config = {'targets':
            [
                'https://abc.api.xxx',
                'https://xyz.abc',
                'https://stackoverflow.net'
            ]};
relay(req, resp, config);               
function relay(req, resp, config) {
    doRelay(req, resp, config['targets'], relayOne);
}

function doRelay(req, resp, servers, relayOne) {
    var finalresponses = [];
    if (servers.length > 0) {
        var loop = function(servers, index, relayOne, done) {
            relayOne(req, servers[index], function(response) {
                finalresponses.push[response];
                if (++index < servers.length) {
                    setTimeout(function(){
                        loop(servers, index, relayOne, done);
                    }, 0);
                } else {
                    done(resp, finalresponses);
                }
            });
        };
        loop(servers, 0, relayOne, done);
    } else {
        done(resp, finalresponses);
    }
}

function relayOne(req, targetserver, relaydone) {
//call the targetserver and return the response data
/*return relaydone(response data);*/
}

function done(resp, finalresponses){
    console.log('ended');
    resp.writeHead(200, 'OK', {
        'Content-Type' : 'text/plain'
    });
    resp.end(finalresponses);
    return;
}
[ 'https://abc.api.xxx', 'https://xyz.abc', 'https://stackoverflow.net' ]}; 继电器(请求、响应、配置); 功能继电器(请求、响应、配置){ doRelay(请求、响应、配置['targets'],中继); } 功能数据库(请求、响应、服务器、中继){ var最终响应=[]; 如果(servers.length>0){ var loop=函数(服务器、索引、中继、完成){ 中继(请求、服务器[索引]、功能(响应){ 最终响应。推送[响应]; 如果(++索引
你问的是一个有点普通的问题,但唯一的答案是为特定问题编写特定的解决方案。如果您不希望fast fail with
Promise.all()
,那么您需要描述您想要什么,并准确地解释您试图实现什么,以便有人可以帮助您编写代码。正如您现在所写的问题,没有通用的方法来回答它,它可能应该关闭。
Promise.all()
的工作方式与它的工作方式相同,因为它是最常见的设计案例。如果你有一个不同的设计目标,你想让我们帮你编码,你必须分享你的设计目标是什么(可能有实际的代码要看)。也请看。很抱歉不清楚。我对问题进行了编辑,使其更加具体。实际上
Promise.all()
并不意味着其他服务器将不会接收您的数据。当您已经将所有请求发送到所有其他服务器,并且您正在等待它们完成或失败时的通知时,通常会使用
Promise.all()
。因此,即使其中一个失败,所有请求都已发送
Promise.all()
只是不会告诉你哪一个成功了或失败了,因为它只会在第一个失败时通知你,或者如果他们都成功了。它们都已发送。听起来OP需要联系多个外部服务器,以便对传入的API调用综合响应。这不是现成的代理知道如何做的事情。我现在看到了问题所在。但从这个问题上看,这并不完全清楚。也许OP应该编辑他们的问题?是的,这就是为什么我对原始问题留下了多条评论,而不是猜测答案,并等待OP澄清。好的,我今天学到了一些关于堆栈溢出礼仪的知识。谢谢是的,很抱歉不清楚。我编辑了
const express = require('express');
const router = express.Router();

const userCtrl = require('../controllers/users');


router.post('/signup', userCtrl.signup);
router.post('/login', userCtrl.login);

module.exports = router;
var config = {'targets':
            [
                'https://abc.api.xxx',
                'https://xyz.abc',
                'https://stackoverflow.net'
            ]};
relay(req, resp, config);               
function relay(req, resp, config) {
    doRelay(req, resp, config['targets'], relayOne);
}

function doRelay(req, resp, servers, relayOne) {
    var finalresponses = [];
    if (servers.length > 0) {
        var loop = function(servers, index, relayOne, done) {
            relayOne(req, servers[index], function(response) {
                finalresponses.push[response];
                if (++index < servers.length) {
                    setTimeout(function(){
                        loop(servers, index, relayOne, done);
                    }, 0);
                } else {
                    done(resp, finalresponses);
                }
            });
        };
        loop(servers, 0, relayOne, done);
    } else {
        done(resp, finalresponses);
    }
}

function relayOne(req, targetserver, relaydone) {
//call the targetserver and return the response data
/*return relaydone(response data);*/
}

function done(resp, finalresponses){
    console.log('ended');
    resp.writeHead(200, 'OK', {
        'Content-Type' : 'text/plain'
    });
    resp.end(finalresponses);
    return;
}