28 Stimmen

Dynamisches Laden von Node.js-Modulen auf der Grundlage von Routen

Ich mache ein Projekt in Node.js mit express. Hier ist meine Verzeichnisstruktur:

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

En lib/api/ enthält eine Reihe von JS-Dateien, die sich auf die API beziehen. Was ich tun muss, ist eine Art von Hooking-System zu machen, dass jedes Mal, wenn eine der API-Funktionen vom Express-HTTP-Server angefordert wird, es tut, was Aktion in der entsprechenden API-Handler angegeben ist. Es ist wahrscheinlich verwirrend, aber hoffentlich bekommen Sie die Idee.

  1. Larry sendet eine POST-Anfrage, um Benutzerdaten zu erhalten.
  2. Server schaut rein lib/api um die mit dieser Anfrage verbundene Funktion zu finden.
  3. Der Server führt die Aktion durch und sendet die Daten an Larry zurück.

Ich hoffe, Sie können mir weiterhelfen. Ich dachte, es könnte mit Prototypen getan werden, aber nicht sicher.

Gracias.

35voto

freakish Punkte 51382

Wenn Sie wissen, wo sich Ihre Skripte befinden, d.h. wenn Sie ein Ausgangsverzeichnis haben, z.B. DIR dann können Sie mit fs zum Beispiel:

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

Nun müssen Ihre Skripte der folgenden Struktur folgen (wegen der require(path)(module_holder) Zeile), zum Beispiel:

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;
};

und jetzt, bei der Bearbeitung einer Anfrage, tun Sie das:

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

Dies sollte alle Ihre Module nach module_holder variabel. Ich habe es nicht getestet, aber es sollte funktionieren ( bis auf die Fehlerbehandlung!!! ). Möglicherweise möchten Sie diese Funktion ändern (z. B. durch module_holder ein Baum, nicht ein einstufiges Wörterbuch), aber ich denke, Sie werden die Idee verstehen.

Diese Funktion sollte bei jedem Serverstart einmal geladen werden (wenn Sie sie häufiger aufrufen müssen, haben Sie es wahrscheinlich mit dynamischem serverseitigem Scripting zu tun und das ist imho eine gaaaanz schlechte Idee). Das einzige, was Sie jetzt noch brauchen, ist der Export von module_holder Objekt, so dass jeder View-Handler es verwenden kann.

7voto

ZiTAL Punkte 3274

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');    
    }
};

Wenn man diesen Code ein wenig dynamisiert, kann man magische Dinge tun :D

3voto

JJ_Coder4Hire Punkte 4424

Hier ist ein Beispiel für einen REST-API-Webdienst, der die Handler-Js-Datei dynamisch auf der Grundlage der an den Server gesendeten URL lädt:

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);

Handler befinden sich in meinem Fall in einem Unterordner /TrainerCentral, so dass die Zuordnung wie folgt funktioniert:

localhost:8080/TrainerCentral/Rezept wird auf die js-Datei /TrainerCentral/Rezept.js abgebildet localhost:8080/TrainerCentral/Workout wird auf die js-Datei /TrainerCentral/Workout.js abgebildet

Hier ist ein Beispiel für einen Handler, der jede der 4 wichtigsten HTTP-Aktionen zum Abrufen, Einfügen, Aktualisieren und Löschen von Daten verarbeiten kann.

/TrainerZentral/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");
   }
};

Starten Sie den Server über die Befehlszeile mit "node index.js".

Viel Spaß!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X