Узел Загрузки.модули JS динамически на основе маршрута

Я делаю проект в узел.js с помощью express. Вот моя структура каталогов:

root
|-start.js
|-server.js
|-lib/
|    api/
|        user_getDetails.js
|        user_register.js

на lib/api/ каталог имеет ряд JS-файлов, относящихся к API. Что мне нужно сделать, это сделать своего рода систему подключения, что всякий раз, когда одна из функций API запрашивается с сервера express HTTP, она выполняет любое действие, указанное в соответствующем обработчике API. Возможно, это сбивает с толку, но, надеюсь, вы поняли.

  1. Ларри отправляет запрос через Post, чтобы получить данные пользователя.
  2. сервер ищет в lib/api чтобы найти функцию, связанную с этим запросом.
  3. сервер выполняет действие и отправляет данные Ларри.

надеюсь, вы можете мне помочь. Я думал, что это можно сделать с помощью прототипов, но не уверен.

спасибо!

3 ответов


если вы знаете, где ваши скрипты, т. е. у вас есть начальный каталог, например DIR, тогда вы можете работать с fs, например:

сервер.js

var fs = require('fs');
var path_module = require('path');
var module_holder = {};

function LoadModules(path) {
    fs.lstat(path, function(err, stat) {
        if (stat.isDirectory()) {
            // we have a directory: do a tree walk
            fs.readdir(path, function(err, files) {
                var f, l = files.length;
                for (var i = 0; i < l; i++) {
                    f = path_module.join(path, files[i]);
                    LoadModules(f);
                }
            });
        } else {
            // we have a file: load it
            require(path)(module_holder);
        }
    });
}
var DIR = path_module.join(__dirname, 'lib', 'api');
LoadModules(DIR);

exports.module_holder = module_holder;
// the usual server stuff goes here

теперь скриптов должны следовать следующей структуре (из-за require(path)(module_holder) строка), например:

user_getDetails.js

function handler(req, res) {
    console.log('Entered my cool script!');
}

module.exports = function(module_holder) {
    // the key in this dictionary can be whatever you want
    // just make sure it won't override other modules
    module_holder['user_getDetails'] = handler;
};

и теперь, при обработке запроса, Вы делаете:

// request is supposed to fire user_getDetails script
module_holder['user_getDetails'](req, res);

это должно загрузить все ваши модули module_holder переменной. Я не тестировал его, но он должен работать (за исключением обработки ошибок!!!). Вы можете изменить эту функцию (например,module_holder дерево, а не словарь одного уровня), но я думаю, вы поймете эту идею.

эта функция должна загружаться один раз за запуск сервера (если вам нужно запускать ее чаще, то вы, вероятно, имеете дело с динамическими серверными скриптами, и это идея baaaaaad, imho). Единственное, что тебе сейчас нужно-это экспорт module_holder объект, чтобы каждый обработчик представления мог его использовать.


app.js

var c_file = 'html.js';

var controller = require(c_file);
var method = 'index';

if(typeof(controller[method])==='function')
    controller[method]();

HTML-код.js

module.exports =
{
    index: function()
    {
        console.log('index method');
    },
    close: function()
    {
        console.log('close method');    
    }
};

немного динамизируя этот код, вы можете делать волшебные вещи: D


вот пример веб-службы REST API, которая динамически загружает JS-файл обработчика на основе url-адреса, отправленного на сервер:

сервер.js

var http = require("http");
var url = require("url");

function start(port, route) {
   function onRequest(request, response) {
       var pathname = url.parse(request.url).pathname;
       console.log("Server:OnRequest() Request for " + pathname + " received.");
       route(pathname, request, response);
   }

   http.createServer(onRequest).listen(port);
   console.log("Server:Start() Server has started.");
}

exports.start = start;

маршрутизатор.js

function route(pathname, req, res) {
    console.log("router:route() About to route a request for " + pathname);

    try {
        //dynamically load the js file base on the url path
        var handler = require("." + pathname);

        console.log("router:route() selected handler: " + handler);

        //make sure we got a correct instantiation of the module
        if (typeof handler["post"] === 'function') {
            //route to the right method in the module based on the HTTP action
            if(req.method.toLowerCase() == 'get') {
                handler["get"](req, res);
            } else if (req.method.toLowerCase() == 'post') {
                handler["post"](req, res);
            } else if (req.method.toLowerCase() == 'put') {
                handler["put"](req, res);
            } else if (req.method.toLowerCase() == 'delete') {
                handler["delete"](req, res);
            }

            console.log("router:route() routed successfully");
            return;
        } 
    } catch(err) {
        console.log("router:route() exception instantiating handler: " + err);
    }

    console.log("router:route() No request handler found for " + pathname);
    res.writeHead(404, {"Content-Type": "text/plain"});
    res.write("404 Not found");
    res.end();

}

exports.route = route;
.js
var server = require("./server");
var router = require("./router");

server.start(8080, router.route);

обработчики в моем случае находятся в подпапке / TrainerCentral, поэтому отображение работает следующим образом:

локальный:8080/TrainerCentral/рецепт карты файл JS /TrainerCentral/рецепт.Яш localhost: 8080 / TrainerCentral / тренировка будет карта в файл js / TrainerCentral / Workout.js

вот пример обработчика, который может обрабатывать каждое из 4 основных действий HTTP для получения, вставки, обновления и удаления данных.

/TrainerCentral/Тренировки.js

function respond(res, code, text) {
    res.writeHead(code, { "Content-Type": "text/plain" });
    res.write(text);
    res.end();
}

module.exports = {
   get: function(req, res) {
       console.log("Workout:get() starting");

       respond(res, 200, "{ 'id': '123945', 'name': 'Upright Rows', 'weight':'125lbs' }");
   },
   post: function(request, res) {
       console.log("Workout:post() starting");

       respond(res, 200, "inserted ok");
   },
   put: function(request, res) {
       console.log("Workout:put() starting");

       respond(res, 200, "updated ok");
   },
   delete: function(request, res) {
       console.log("Workout:delete() starting");

       respond(res, 200, "deleted ok");
   }
};

запустите сервер из командной строки с помощью " Node index.js"

удачи!