根据路由动态加载Node.js模块

时间:2012-06-06 13:02:26

标签: javascript api node.js prototype v8

我正在使用express在Node.js中做一个项目。这是我的目录结构:

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

lib/api/目录有许多与API相关的JS文件。我需要做的是制作一种挂钩系统,无论何时从快速HTTP服务器请求其中一个API函数,它都会执行相应API处理程序中指定的任何操作。这可能令人困惑,但希望你能得到这个想法。

  1. Larry通过POST发送请求以获取用户详细信息。
  2. 服务器查找lib/api以查找与该请求关联的功能。
  3. 服务器执行操作并将数据发送回Larry。
  4. 希望你能帮助我。我当时认为可以使用原型来完成,但不确定。

    谢谢!

3 个答案:

答案 0 :(得分:28)

如果您知道脚本的位置,即您有一个初始目录,例如DIR,那么您可以使用fs,例如:

<强> server.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对象,以便每个视图处理程序都可以使用它。

答案 1 :(得分:4)

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

答案 2 :(得分:2)

以下是REST API Web服务的示例,该服务根据发送到服务器的url动态加载处理程序js文件:

server.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;

router.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;

index.js

var server = require("./server");
var router = require("./router");

server.start(8080, router.route);
在我的情况下,

处理程序位于子文件夹/ TrainerCentral中,因此映射的工作原理如下:

localhost:8080 / TrainerCentral / Recipe将映射到js文件/TrainerCentral/Recipe.js localhost:8080 / TrainerCentral / Workout将映射到js文件/TrainerCentral/Workout.js

这是一个示例处理程序,可以处理用于检索,插入,更新和删除数据的4个主要HTTP操作中的每一个。

/TrainerCentral/Workout.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”从命令行启动服务器

玩得开心!