2012-06-06 29 views
14

Tôi đang thực hiện một dự án trong Node.js bằng cách sử dụng express. Dưới đây là cấu trúc thư mục của tôi:Tải các mô đun Node.js động dựa trên tuyến đường

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

Thư mục lib/api/ có một số file JS liên quan đến API. Những gì tôi cần làm là tạo một hệ thống hooking, bất cứ khi nào một trong các hàm API được yêu cầu từ máy chủ HTTP tốc hành, nó thực hiện bất kỳ hành động nào được chỉ định trong trình xử lý API theo. Nó có thể gây nhầm lẫn, nhưng hy vọng bạn có được ý tưởng.

  1. Larry gửi yêu cầu qua POST để nhận chi tiết người dùng.
  2. Máy chủ sẽ tìm kiếm trong lib/api để tìm chức năng được liên kết với yêu cầu đó.
  3. Máy chủ thực hiện hành động và gửi lại dữ liệu cho Larry.

Hy vọng bạn có thể giúp tôi. Tôi đã nghĩ rằng nó có thể được thực hiện bằng cách sử dụng nguyên mẫu, không chắc chắn mặc dù.

Cảm ơn!

+0

Tôi không chắc mình hiểu. Bạn chỉ cần thực hiện 'var m = require ('./ lib/api/user_getDetails.js')' và sử dụng mô đun đó trong câu trả lời của bạn. Tui bỏ lỡ điều gì vậy? – freakish

+0

Tôi muốn tải động. Tức là, nếu tôi thêm một hàm API mới, tôi không phải tự yêu cầu nó. Nhưng tôi không chắc chắn làm thế nào để thực hiện điều này. –

+0

Vì vậy, bạn muốn có một bộ nạp tự động? –

Trả lời

23

Nếu bạn biết nơi kịch bản của bạn được, tức là bạn có một thư mục ban đầu, ví dụ DIR, sau đó bạn có thể làm việc với fs, ví dụ:

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 

Bây giờ tập lệnh của bạn cần phải theo cấu trúc sau (vì đường dây require(path)(module_holder)), ví dụ:

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

và bây giờ, khi xử lý một yêu cầu, bạn cần làm:

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

này sẽ tải tất cả các module của bạn để module_holder biến. Tôi đã không kiểm tra nó, nhưng nó sẽ hoạt động (ngoại trừ việc xử lý lỗi !!!). Bạn có thể muốn thay đổi chức năng này (ví dụ: làm cho module_holder một cây, không phải là một từ điển cấp một) nhưng tôi nghĩ bạn sẽ nắm bắt được ý tưởng đó.

Chức năng này sẽ tải một lần cho mỗi lần khởi động máy chủ (nếu bạn cần kích hoạt nó thường xuyên hơn, thì có thể bạn đang xử lý kịch bản lệnh phía máy chủ động và đây là ý tưởng baaaaaad, imho). Điều duy nhất bạn cần bây giờ là xuất khẩu đối tượng module_holder để mọi trình xử lý chế độ xem có thể sử dụng nó.

+1

Nếu bạn đang gọi chức năng này một lần khi khởi động, không có lý do gì để sử dụng các phiên bản không đồng bộ; chỉ cần sử dụng 'fs.lstatSync' và' fs.readdirSync'. Điều đó cũng khiến bạn không thể nuốt các lỗi vì các ngoại lệ sẽ được ném ra, thay vì các lỗi được chuyển tới các cuộc gọi lại và sau đó bị bỏ qua. – Domenic

+0

@Domenic True. Bằng cách nào đó tôi đã quen với việc lập trình không đồng bộ và không còn nghĩ đồng bộ nữa, hehe. :) Nhân tiện, bạn đã xóa bỏ khối 'try {} catch {}' của mình. Thật vậy, nó không cần thiết ở đây, kể từ khi kịch bản sẽ tiếp tục làm việc ngay cả khi các mô-đun ném một ngoại lệ. Nhưng điều này không còn đúng với các phiên bản đồng bộ nữa! – freakish

+0

Câu trả lời tuyệt vời, nhưng tôi vẫn còn nhầm lẫn về cách làm cho máy chủ sử dụng các mô-đun ... Một giải pháp lý tưởng sẽ bằng cách nào đó sử dụng một hệ thống dựa trên nguyên mẫu tôi có thể mở rộng (nếu điều đó có ý nghĩa). Bất kể tải tập lệnh nào nên có thứ gì đó như 'Hook.add (" user_getDetails "); Hook.user_getDetails.action = function() {console.log ("phương thức user_getDetails được gọi!")}; ' Một cái gì đó tương tự, mặc dù tôi không biết làm thế nào nó sẽ hoạt động: P –

3

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

dynamizing mã này một chút bạn có thể làm những điều kỳ diệu: D

+1

Tôi nghĩ rằng nó nên được nếu (typeof (điều khiển [phương pháp]) == 'chức năng') – zephyr

+0

bạn là đúng @ zephyr – ZiTAL

1

Dưới đây là một ví dụ về một dịch vụ web API REST rằng động tải tập tin handler js dựa trên url gửi đến máy chủ :

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

xử lý trong trường hợp của tôi đang ở trong một thư mục con/TrainerCentral, vì vậy việc lập bản đồ các công trình như thế này:

localhost: 8080/TrainerCentral/Recipe sẽ ánh xạ tập tin js/TrainerCentral /Recipe.js localhost: 8080/TrainerCentral/Workout sẽ ánh xạ tới tệp js /TrainerCentral/Workout.js

đây là trình xử lý ví dụ có thể xử lý từng hành động HTTP chính để truy xuất, chèn, cập nhật và xóa dữ liệu.

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

khởi động server từ dòng lệnh với "index.js nút"

Have fun!

Các vấn đề liên quan