mirror of
https://github.com/thinkjs/thinkjs.git
synced 2026-01-18 14:26:56 +00:00
重构App.js
This commit is contained in:
parent
e62cbbee16
commit
f70a01a924
@ -155,6 +155,7 @@
|
||||
"BELONGS_TO": true,
|
||||
"HAS_MANY": true,
|
||||
"MANY_TO_MANY": true,
|
||||
"isDate": true
|
||||
"isDate": true,
|
||||
"getThinkRequirePath": true
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -9,7 +9,7 @@ var _autoload_callbacks = [];
|
||||
* @param {[type]} name [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
function getThinkRequirePath(name){
|
||||
global.getThinkRequirePath = function(name){
|
||||
'use strict';
|
||||
if (_alias[name]) {
|
||||
return _alias[name];
|
||||
@ -113,6 +113,7 @@ global.tag = function(name, http, data){
|
||||
}
|
||||
var result = B(behavior, http, http.tag_data);
|
||||
return getPromise(result).then(function(data){
|
||||
//如果返回值不是undefined,那么认为有返回值
|
||||
if (data !== undefined) {
|
||||
http.tag_data = data;
|
||||
}
|
||||
@ -134,6 +135,7 @@ global.C = function(name, value){
|
||||
//清除所有的配置
|
||||
if (name === null) {
|
||||
_config = {};
|
||||
return;
|
||||
}
|
||||
if (isString(name)) {
|
||||
name = name.toLowerCase();
|
||||
@ -164,13 +166,8 @@ global.C = function(name, value){
|
||||
*/
|
||||
global.A = function(name, http, data){
|
||||
'use strict';
|
||||
if (name.indexOf('/') > -1) {
|
||||
name = name.split('/');
|
||||
}else if (name.indexOf(':') > -1) {
|
||||
name = name.split(':');
|
||||
}else{
|
||||
name = [name];
|
||||
}
|
||||
//将/转为:,兼容之前的方式
|
||||
name = name.replace(/\//g, ':').split(':');
|
||||
var action;
|
||||
if (name.length === 3) {
|
||||
action = name.pop();
|
||||
|
||||
@ -12,7 +12,7 @@ module.exports = {
|
||||
Dispatcher: THINK_LIB_PATH + '/Core/Dispatcher.js',
|
||||
Filter: THINK_LIB_PATH + '/Util/Filter.js',
|
||||
Http: THINK_LIB_PATH + '/Core/Http.js',
|
||||
Log: THINK_LIB_PATH + '/Util/Log.js',
|
||||
//Log: THINK_LIB_PATH + '/Util/Log.js',
|
||||
Model: THINK_LIB_PATH + '/Core/Model.js',
|
||||
Session: THINK_LIB_PATH + '/Util/Session.js',
|
||||
Think: THINK_LIB_PATH + '/Core/Think.js',
|
||||
|
||||
@ -26,8 +26,8 @@ module.exports = {
|
||||
default_action: 'index', //默认Action
|
||||
call_controller: 'Home:Index:_404', //controller不存在时执行方法,此配置表示调用Home分组下IndexController的_404Action方法
|
||||
call_method: '__call', //当找不到方法时调用什么方法,这个方法存在时才有效
|
||||
before_action_name: '__before', //调用一个action前调用的方法,会将action名传递进去
|
||||
after_action_name: '__after', //调用一个action之后调用的方法,会将action名传递进去
|
||||
before_action: '__before', //调用一个action前调用的方法,会将action名传递进去
|
||||
after_action: '__after', //调用一个action之后调用的方法,会将action名传递进去
|
||||
url_params_bind: true, //方法参数绑定,将URL参数值绑定到action的参数上
|
||||
action_suffix: 'Action', //action后缀
|
||||
url_callback_name: 'callback', //jsonp格式的callback名字
|
||||
|
||||
@ -1,176 +1,173 @@
|
||||
var cluster = require('cluster');
|
||||
var fs = require('fs');
|
||||
var domain = require('domain');
|
||||
|
||||
var thinkHttp = thinkRequire('Http');
|
||||
var Dispatcher = thinkRequire('Dispatcher');
|
||||
|
||||
/**
|
||||
* 应用程序
|
||||
* @type {Object}
|
||||
*/
|
||||
var App = module.exports = Class(function(){
|
||||
'use strict';
|
||||
//controller和action的校验正则
|
||||
var nameReg = /^[A-Za-z\_](\w)*$/;
|
||||
//注释的正则
|
||||
var commentReg = /((\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s))/mg;
|
||||
//获取形参的正则
|
||||
var parsReg = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
|
||||
//注释的正则
|
||||
var commentReg = /((\/\/.*$)|(\/\*[\s\S]*?\*\/)|(\s))/mg;
|
||||
//获取形参的正则
|
||||
var parsReg = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
|
||||
|
||||
return {
|
||||
init: function(http){
|
||||
this.http = http;
|
||||
},
|
||||
/**
|
||||
* 解析路由
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
dispatch: function(){
|
||||
return Dispatcher(this.http).run();
|
||||
},
|
||||
/**
|
||||
* 获取controller
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
getController: function(){
|
||||
var group = this.http.group;
|
||||
var controller = '';
|
||||
//检测controller名
|
||||
if (nameReg.test(this.http.controller)) {
|
||||
controller = A(group + '/' + this.http.controller, this.http);
|
||||
if (controller) {
|
||||
return controller;
|
||||
}
|
||||
}
|
||||
//controller不存在时调用的魔术方法
|
||||
var controllerConf = C('call_controller');
|
||||
if (controllerConf) {
|
||||
if (isString(controllerConf)) {
|
||||
controllerConf = controllerConf.split(':');
|
||||
}
|
||||
var action = Dispatcher.getAction(controllerConf.pop());
|
||||
controller = Dispatcher.getController(controllerConf.pop());
|
||||
group = Dispatcher.getGroup(controllerConf.pop());
|
||||
controller = A(group + '/' + controller, this.http);
|
||||
if (controller && isFunction(controller[action + C('action_suffix')])) {
|
||||
this.http.group = group;
|
||||
this.http.controller = controller;
|
||||
this.http.action = action;
|
||||
return controller;
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 执行
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
exec: function(){
|
||||
var controller = this.getController();
|
||||
if (!controller) {
|
||||
var err = new Error('Controller `' + this.http.controller + '` not found. ' + this.http.pathname);
|
||||
return getPromise(err, true);
|
||||
}
|
||||
var self = this;
|
||||
var action = this.http.action;
|
||||
var act = action;
|
||||
//添加action后缀
|
||||
action += C('action_suffix') || '';
|
||||
//检测action名
|
||||
if (!nameReg.test(action)) {
|
||||
return getPromise(new Error('action `' + act + '` is not valid. ' + this.http.pathname), true);
|
||||
}
|
||||
var initReturnPromise = getPromise(controller.__initReturn);
|
||||
//对应的action方法存在
|
||||
if (isFunction(controller[action])) {
|
||||
//方法参数自动绑定,直接从形参里拿到对应的值
|
||||
if (C('url_params_bind')) {
|
||||
var toString = controller[action].toString().replace(commentReg, '');
|
||||
var match = toString.match(parsReg)[1].split(/,/).filter(function(item){
|
||||
return item;
|
||||
});
|
||||
//匹配到形参
|
||||
if (match && match.length) {
|
||||
return initReturnPromise.then(function(){
|
||||
var data = match.map(function(item){
|
||||
return self.http.post[item] || self.http.get[item] || '';
|
||||
});
|
||||
return self.execAction(controller, action, act, data);
|
||||
});
|
||||
}
|
||||
}
|
||||
return initReturnPromise.then(function(){
|
||||
return self.execAction(controller, action, act);
|
||||
});
|
||||
}else{
|
||||
//当指定的方法不存在时,调用魔术方法
|
||||
//默认为__call方法
|
||||
var callMethod = C('call_method');
|
||||
if (callMethod && isFunction(controller[callMethod])) {
|
||||
return initReturnPromise.then(function(){
|
||||
return controller[callMethod](act, action);
|
||||
});
|
||||
}
|
||||
}
|
||||
return getPromise(new Error('action `' + action + '` not found. ' + self.http.pathname), true);
|
||||
},
|
||||
/**
|
||||
* 执行一个action, 支持before和after的统一操作
|
||||
* 不对每个action都增加一个before和after,而是使用统一的策略
|
||||
* 默认before和after调用名__before和__after
|
||||
* @param {[type]} controller [description]
|
||||
* @param {[type]} action [description]
|
||||
* @param {[type]} act [description]
|
||||
* @param {[type]} data [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
execAction: function(controller, action, act, data){
|
||||
var promise = getPromise();
|
||||
//before action
|
||||
var before = C('before_action_name');
|
||||
if (before && isFunction(controller[before])) {
|
||||
promise = getPromise(controller[before](act, action));
|
||||
}
|
||||
return promise.then(function(){
|
||||
if (data) {
|
||||
return controller[action].apply(controller, data)
|
||||
}else{
|
||||
return controller[action]()
|
||||
}
|
||||
}).then(function(){
|
||||
//after action
|
||||
var after = C('after_action_name');
|
||||
if (after && isFunction(controller[after])) {
|
||||
return controller[after](act, action);
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 发送错误信息
|
||||
* @param {[type]} error [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
sendError: function(error){
|
||||
var message = isError(error) ? error.stack : error;
|
||||
var http = this.http;
|
||||
console.log(message);
|
||||
if (!http.res) {
|
||||
return;
|
||||
}
|
||||
if (APP_DEBUG) {
|
||||
http.res.statusCode = 500;
|
||||
http.res.end(message);
|
||||
}else{
|
||||
http.res.statusCode = 500;
|
||||
http.setHeader('Content-Type', 'text/html; charset=' + C('encoding'));
|
||||
var readStream = fs.createReadStream(C('error_tpl_path'));
|
||||
readStream.pipe(http.res);
|
||||
readStream.on('end', function(){
|
||||
http.res.end();
|
||||
});
|
||||
}
|
||||
|
||||
var App = module.exports = {};
|
||||
/**
|
||||
* 根据http里的group和controller获取对应的controller实例
|
||||
* @param {[type]} http [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
App.getBaseController = function(http){
|
||||
'use strict';
|
||||
var gc = ucfirst(http.group) + '/' + ucfirst(http.controller) + 'Controller';
|
||||
var path = getThinkRequirePath(gc);
|
||||
if (path) {
|
||||
return require(path)(http);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* controller不存在时调用的默认controller
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
App.getCallController = function(http){
|
||||
'use strict';
|
||||
var config = C('call_controller');
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
if (isString(config)) {
|
||||
config = config.split(':');
|
||||
}
|
||||
var action = Dispatcher.getAction(config.pop());
|
||||
var controller = Dispatcher.getController(config.pop());
|
||||
var group = Dispatcher.getGroup(config.pop());
|
||||
var instance = this.getBaseController({
|
||||
group: group,
|
||||
controller: controller
|
||||
})
|
||||
if (instance && isFunction(instance[action + C('action_suffix')])) {
|
||||
http.group = group;
|
||||
http.controller = controller;
|
||||
http.action = action;
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行具体的action,调用前置和后置操作
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
App.execAction = function(controller, action, data, callMethod){
|
||||
'use strict';
|
||||
//action操作
|
||||
var act = action + C('action_suffix');
|
||||
var flag = false;
|
||||
//action不存在时执行魔术方法
|
||||
if (callMethod && !isFunction(controller[act])) {
|
||||
var call = C('call_method');
|
||||
if (call && isFunction(controller[call])) {
|
||||
flag = true;
|
||||
act = call;
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
//action不存在
|
||||
if (!isFunction(controller[act])) {
|
||||
return getPromise('action `' + action + '` not found. ', true);
|
||||
}
|
||||
var promise = getPromise();
|
||||
//action前置操作
|
||||
var before = C('before_action');
|
||||
if (before && isFunction(controller[before])) {
|
||||
promise = controller[before](action);
|
||||
}
|
||||
promise = promise.then(function(){
|
||||
//action魔术方法只传递action参数
|
||||
if (flag) {
|
||||
return controller[act](action);
|
||||
}
|
||||
if (data) {
|
||||
return controller[act].apply(controller, data);
|
||||
}else{
|
||||
return controller[act]();
|
||||
}
|
||||
});
|
||||
//action后置操作
|
||||
var after = C('after_action');
|
||||
if (after && isFunction(controller[after])) {
|
||||
promise = promise.then(function(){
|
||||
return controller[after](action);
|
||||
})
|
||||
}
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取action的形参
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
App.getActionParams = function(fn, http){
|
||||
'use strict';
|
||||
var toString = fn.toString().replace(commentReg, '');
|
||||
var match = toString.match(parsReg)[1].split(/\s*,\s*/);
|
||||
//匹配到形参
|
||||
var params;
|
||||
if (match && match.length) {
|
||||
params = match.map(function(item){
|
||||
return http.post[item] || http.get[item] || '';
|
||||
});
|
||||
}
|
||||
return params;
|
||||
}
|
||||
/**
|
||||
* 执行
|
||||
* @param {[type]} http [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
App.exec = function(http){
|
||||
'use strict';
|
||||
var controller = this.getBaseController(http) || this.getCallController(http);
|
||||
//controller不存在
|
||||
if (!controller) {
|
||||
var err = new Error('Controller `' + http.controller + '` not found. ' + http.pathname);
|
||||
return getPromise(err, true);
|
||||
}
|
||||
var params;
|
||||
var actionFn = controller[http.action + C('action_suffix')];
|
||||
//参数绑定
|
||||
if (C('url_params_bind') && isFunction(actionFn)) {
|
||||
params = this.getActionParams(actionFn, http);
|
||||
}
|
||||
var promise = getPromise(controller.__initReturn);
|
||||
var self = this;
|
||||
return promise.then(function(){
|
||||
return self.execAction(controller, http.action, params, true);
|
||||
})
|
||||
}
|
||||
/**
|
||||
* 发送错误信息
|
||||
* @param {[type]} error [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
App.sendError = function(http, error){
|
||||
'use strict';
|
||||
var message = isError(error) ? error.stack : error;
|
||||
console.log(message);
|
||||
if (!http.res) {
|
||||
return;
|
||||
}
|
||||
if (APP_DEBUG) {
|
||||
http.res.statusCode = 500;
|
||||
http.res.end(message);
|
||||
}else{
|
||||
http.res.statusCode = 500;
|
||||
http.setHeader('Content-Type', 'text/html; charset=' + C('encoding'));
|
||||
var readStream = fs.createReadStream(C('error_tpl_path'));
|
||||
readStream.pipe(http.res);
|
||||
readStream.on('end', function(){
|
||||
http.res.end();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* run
|
||||
@ -254,26 +251,25 @@ App.listener = function(http){
|
||||
http.res.end();
|
||||
return getDefer().promise;
|
||||
}
|
||||
var instance = App(http);
|
||||
var domainInstance = domain.create();
|
||||
var deferred = getDefer();
|
||||
domainInstance.on('error', function(err){
|
||||
instance.sendError(err);
|
||||
App.sendError(http, err);
|
||||
deferred.reject(err);
|
||||
});
|
||||
domainInstance.run(function(){
|
||||
return tag('app_init', http).then(function(){
|
||||
return instance.dispatch();
|
||||
return Dispatcher(http).run();
|
||||
}).then(function(){
|
||||
return tag('app_begin', http);
|
||||
}).then(function(){
|
||||
return tag('action_init', http);
|
||||
}).then(function(){
|
||||
return instance.exec();
|
||||
return App.exec(http);
|
||||
}).then(function(){
|
||||
return tag('app_end', http);
|
||||
}).catch(function(err){
|
||||
instance.sendError(err);
|
||||
App.sendError(http, err);
|
||||
}).then(function(){
|
||||
deferred.resolve();
|
||||
})
|
||||
|
||||
@ -80,7 +80,6 @@ var Dispatcher = module.exports = Class(function(){
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取group
|
||||
* @param {[type]} group [description]
|
||||
@ -91,6 +90,12 @@ Dispatcher.getGroup = function(group){
|
||||
group = group || C('default_group');
|
||||
return ucfirst(group);
|
||||
};
|
||||
|
||||
/**
|
||||
* 检测Controller和Action是否合法的正则
|
||||
* @type {RegExp}
|
||||
*/
|
||||
var nameReg = /^[A-Za-z\_](\w)*$/;
|
||||
/**
|
||||
* 获取controller
|
||||
* @param {[type]} controller [description]
|
||||
@ -98,7 +103,9 @@ Dispatcher.getGroup = function(group){
|
||||
*/
|
||||
Dispatcher.getController = function(controller){
|
||||
'use strict';
|
||||
controller = controller || C('default_controller');
|
||||
if (!controller || !nameReg.test(controller)) {
|
||||
return ucfirst(C('default_controller'));
|
||||
}
|
||||
return ucfirst(controller);
|
||||
};
|
||||
/**
|
||||
@ -108,6 +115,8 @@ Dispatcher.getController = function(controller){
|
||||
*/
|
||||
Dispatcher.getAction = function(action){
|
||||
'use strict';
|
||||
action = action || C('default_action');
|
||||
if (!action || !nameReg.test(action)) {
|
||||
return C('default_action');
|
||||
}
|
||||
return action;
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user