我构建了一个nodejs服务器来充当适配器服务器,该服务器在接收到包含某些数据的发布请求后,从请求主体中提取数据,然后将其转发给其他一些外部服务器。最后,我的服务器将发送一个包含每个外部服务器响应的响应(成功/失败)。
如果只有1个端点要转发,这似乎很简单。但是,当我必须转发到多个服务器时,我必须依赖Promise.All()之类的东西,它具有快速响应的行为。这意味着,如果一个承诺被拒绝(外部服务器已关闭),所有其他承诺也将立即被拒绝,其余服务器将无法接收我的数据。
答案 0 :(得分:4)
这可能不是确切的解决方案。但是,我发布的内容可能是解决您的问题的方法。
几天前,我遇到了同样的问题,因为我想实现API版本控制。这是我实现的解决方案,请看看。
让我解释一下这个图
在此图中,是我们所做的服务器的初始配置。所有到达这里的api请求都将传递到发布目录中的“ index.js”文件。
index.js(在发行目录中)
const express = require('express');
const fid = require('./core/file.helper');
const router = express.Router();
fid.getFiles(__dirname,'./release').then(releases => {
releases.forEach(release => {
// release = release.replace(/.js/g,'');
router.use(`/${release}`,require(`./release/${release}/index`))
})
})
module.exports = router
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中,实际上都映射到端点文件夹中的每个端点。
以下是其中一个端点的代码
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;
实际上,在此文件中,我们正在将端点连接到其控制器。
答案 1 :(得分:0)
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;
}
答案 2 :(得分:-1)
听起来您正在尝试设计反向代理。如果您在努力使自定义代码正常工作,则有一个免费的npm库,它非常强大。
我建议使用node-http-proxy
我在下面发布了链接,由于您在问题中提到了对API格式的修改,因此您可以直接转到“修改响应”。不过,请务必阅读整个页面。
https://github.com/http-party/node-http-proxy#modify-a-response-from-a-proxied-server
注意:该库也非常好,因为它可以支持SSL,并且可以同时代理localhost(同一台计算机上的服务器)和其他计算机上的服务器(远程)。
答案 3 :(得分:-1)
Promise.all()
来自MDN
它拒绝的原因是第一个承诺被拒绝。
要解决该问题,您需要catch()
进行每个请求。
例如
Promise.all([
request('<url 1>').catch(err => /* .. error handling */),
request('<url 2>').catch(err => /* .. error handling */),
request('<url 3>').catch(err => /* .. error handling */)
])
.then(([result1, result2, result3]) => {
if(result1.err) { }
if(result2.err) { }
if(result3.err) { }
})