Điều này là để giúp những người khác có thể thấy mình trong tình huống tương tự như tôi đã làm. Tôi hy vọng rằng nó có thể được tiêu chuẩn hóa. Tôi không nghĩ chúng ta nên phát minh lại bánh xe mỗi khi ai đó cần làm đơn đăng ký nhiều người thuê.
Ví dụ này mô tả cấu trúc nhiều người thuê nhà với mỗi khách hàng có cơ sở dữ liệu riêng, giống như tôi đã nói có thể có cách tốt hơn để thực hiện việc này, nhưng vì bản thân tôi không nhận được sự trợ giúp nên đây là giải pháp của tôi.
Vì vậy, đây là các mục tiêu mà giải pháp này nhắm tới:
- mỗi khách hàng được xác định bằng tên miền phụ, ví dụ:client1.application.com,
- ứng dụng kiểm tra xem miền phụ có hợp lệ không,
- ứng dụng tra cứu và lấy thông tin kết nối (url cơ sở dữ liệu, thông tin đăng nhập, v.v.) từ cơ sở dữ liệu chính, ứng dụng
- kết nối với cơ sở dữ liệu ứng dụng khách (giao khá nhiều cho ứng dụng khách), Ứng dụng
- thực hiện các biện pháp để đảm bảo tính toàn vẹn và quản lý tài nguyên (ví dụ:sử dụng cùng một kết nối cơ sở dữ liệu cho các thành viên của cùng một ứng dụng, thay vì tạo kết nối mới).
Đây là mã
trong app.js
của bạn tệp
app.use(clientListener()); // checks and identify valid clients
app.use(setclientdb());// sets db for valid clients
Tôi đã tạo hai phần mềm trung gian:
-
clientListener
- để xác định khách hàng đang kết nối, -
setclientdb
- lấy thông tin chi tiết về máy khách từ cơ sở dữ liệu Chính, sau khi máy khách được xác định, sau đó thiết lập kết nối với cơ sở dữ liệu máy khách.
phần mềm trung gian clientListener
Tôi kiểm tra xem khách hàng là ai bằng cách kiểm tra miền phụ từ đối tượng yêu cầu. Tôi thực hiện một loạt các kiểm tra để đảm bảo rằng ứng dụng khách hợp lệ (tôi biết mã này rất lộn xộn và có thể được làm sạch hơn). Sau khi đảm bảo khách hàng hợp lệ, tôi lưu trữ thông tin khách hàng trong phiên. Tôi cũng kiểm tra xem nếu thông tin máy khách đã được lưu trữ trong phiên thì không cần phải truy vấn lại cơ sở dữ liệu. Chúng tôi chỉ cần đảm bảo rằng miền phụ yêu cầu khớp với miền phụ đã được lưu trữ trong phiên.
var Clients = require('../models/clients');
var basedomain = dbConfig.baseDomain;
var allowedSubs = {'admin':true, 'www':true };
allowedSubs[basedomain] = true;
function clientlistener() {
return function(req, res, next) {
//console.dir('look at my sub domain ' + req.subdomains[0]);
// console.log(req.session.Client.name);
if( req.subdomains[0] in allowedSubs || typeof req.subdomains[0] === 'undefined' || req.session.Client && req.session.Client.name === req.subdomains[0] ){
//console.dir('look at the sub domain ' + req.subdomains[0]);
//console.dir('testing Session ' + req.session.Client);
console.log('did not search database for '+ req.subdomains[0]);
//console.log(JSON.stringify(req.session.Client, null, 4));
next();
}
else{
Clients.findOne({subdomain: req.subdomains[0]}, function (err, client) {
if(!err){
if(!client){
//res.send(client);
res.send(403, 'Sorry! you cant see that.');
}
else{
console.log('searched database for '+ req.subdomains[0]);
//console.log(JSON.stringify(client, null, 4));
//console.log(client);
// req.session.tester = "moyo cow";
req.session.Client = client;
return next();
}
}
else{
console.log(err);
return next(err)
}
});
}
}
}
module.exports = clientlistener;
phần mềm trung gian setclientdb:
Tôi kiểm tra lại mọi thứ để đảm bảo rằng máy khách hợp lệ. Sau đó, kết nối với cơ sở dữ liệu của khách hàng với thông tin được truy xuất từ phiên được mở.
Tôi cũng đảm bảo lưu trữ tất cả các kết nối đang hoạt động vào một đối tượng toàn cục, để ngăn các kết nối mới đến cơ sở dữ liệu theo mỗi yêu cầu (chúng tôi không muốn làm quá tải mỗi máy chủ mongodb của máy khách có kết nối).
var mongoose = require('mongoose');
//var dynamicConnection = require('../models/dynamicMongoose');
function setclientdb() {
return function(req, res, next){
//check if client has an existing db connection /*** Check if client db is connected and pooled *****/
if(/*typeof global.App.clientdbconn === 'undefined' && */ typeof(req.session.Client) !== 'undefined' && global.App.clients[req.session.Client.name] !== req.subdomains[0])
{
//check if client session, matches current client if it matches, establish new connection for client
if(req.session.Client && req.session.Client.name === req.subdomains[0] )
{
console.log('setting db for client ' + req.subdomains[0]+ ' and '+ req.session.Client.dbUrl);
client = mongoose.createConnection(req.session.Client.dbUrl /*, dbconfigoptions*/);
client.on('connected', function () {
console.log('Mongoose default connection open to ' + req.session.Client.name);
});
// When the connection is disconnected
client.on('disconnected', function () {
console.log('Mongoose '+ req.session.Client.name +' connection disconnected');
});
// If the Node process ends, close the Mongoose connection
process.on('SIGINT', function() {
client.close(function () {
console.log(req.session.Client.name +' connection disconnected through app termination');
process.exit(0);
});
});
//If pool has not been created, create it and Add new connection to the pool and set it as active connection
if(typeof(global.App.clients) === 'undefined' || typeof(global.App.clients[req.session.Client.name]) === 'undefined' && typeof(global.App.clientdbconn[req.session.Client.name]) === 'undefined')
{
clientname = req.session.Client.name;
global.App.clients[clientname] = req.session.Client.name;// Store name of client in the global clients array
activedb = global.App.clientdbconn[clientname] = client; //Store connection in the global connection array
console.log('I am now in the list of active clients ' + global.App.clients[clientname]);
}
global.App.activdb = activedb;
console.log('client connection established, and saved ' + req.session.Client.name);
next();
}
//if current client, does not match session client, then do not establish connection
else
{
delete req.session.Client;
client = false;
next();
}
}
else
{
if(typeof(req.session.Client) === 'undefined')
{
next();
}
//if client already has a connection make it active
else{
global.App.activdb = global.App.clientdbconn[req.session.Client.name];
console.log('did not make new connection for ' + req.session.Client.name);
return next();
}
}
}
}
module.exports = setclientdb;
Cuối cùng nhưng không kém phần quan trọng
Vì tôi đang sử dụng kết hợp mongoose và native mongo, Chúng tôi phải biên dịch các mô hình của chúng tôi tại thời điểm chạy. Vui lòng xem bên dưới
Thêm cái này vào app.js
của bạn
// require your models directory
var models = require('./models');
// Create models using mongoose connection for use in controllers
app.use(function db(req, res, next) {
req.db = {
User: global.App.activdb.model('User', models.agency_user, 'users')
//Post: global.App.activdb.model('Post', models.Post, 'posts')
};
return next();
});
Giải thích:
Giống như tôi đã nói trước đó, tôi đã tạo một đối tượng toàn cục để lưu trữ đối tượng kết nối cơ sở dữ liệu đang hoạt động:global.App.activdb
Sau đó, tôi sử dụng đối tượng kết nối này để tạo (biên dịch) mô hình mongoose, sau khi tôi lưu trữ nó trong thuộc tính db của đối tượng req:req.db
. Tôi làm điều này để tôi có thể truy cập các mô hình của mình trong bộ điều khiển như thế này chẳng hạn.
Ví dụ về bộ điều khiển Người dùng của tôi:
exports.list = function (req, res) {
req.db.User.find(function (err, users) {
res.send("respond with a resource" + users + 'and connections ' + JSON.stringify(global.App.clients, null, 4));
console.log('Worker ' + cluster.worker.id + ' running!');
});
};
Cuối cùng tôi sẽ quay lại và dọn dẹp nó. Nếu có ai muốn giúp tôi, điều đó thật tốt.