Как эффективно перенаправить запрос на несколько конечных точек, используя nodejs? - PullRequest
0 голосов
/ 09 июля 2019

Я создал сервер nodejs, который будет выступать в качестве сервера-адаптера, который после получения почтового запроса, содержащего некоторые данные, извлекает данные из тела запроса и затем перенаправляет их на несколько других внешних серверов.Наконец, мой сервер отправит ответ, состоящий из ответов от каждого внешнего сервера (успех / сбой).

Если есть только 1 конечная точка для пересылки, это кажется довольно простым.Однако, когда мне нужно перенаправить более чем на один сервер, я должен полагаться на такие вещи, как Promise.All (), который работает безотказно.Это означает, что если одно обещание будет отклонено (внешний сервер не работает), все остальные обещания также будут немедленно отклонены, а остальные серверы не получат мои данные.

Ответы [ 4 ]

4 голосов
/ 09 июля 2019

Может быть, это не точное решение.Но то, что я публикую, может обойти вашу проблему.

Несколько дней назад у меня возникла та же проблема, что и для реализации контроля версий 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 внутри каждой папки версии

Ниже приведен код для "index.js" внутри v1 или v2 ...

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;

Здесь, в этом файле, мы на самом деле подключаем конечные точки к его контроллерам.

0 голосов
/ 09 июля 2019
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;
}
0 голосов
/ 09 июля 2019

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) { }

})
0 голосов
/ 09 июля 2019

Похоже, вы пытаетесь создать обратный прокси .Если вы пытаетесь заставить работать собственный код, есть бесплатная библиотека npm, которая очень надежна.

Я бы порекомендовал node-http-proxy

Я разместил ссылку ниже, которая будетприведет вас непосредственно к «изменению ответа», так как вы упомянули изменение формата API в своем вопросе.Обязательно прочитайте всю страницу.

https://github.com/http-party/node-http-proxy#modify-a-response-from-a-proxied-server

Примечание: эта библиотека также очень хороша, потому что она может поддерживать SSL и прокси на обоих локальных хостах (серверах на одной машине)и серверы на других машинах (удаленно).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...