/**
* 检测路由行为
* 通过自定义路由识别到对应的URL上
* @return {[type]} [description]
*/
var url = require('url');
var Dispatcher = thinkRequire('Dispatcher');
module.exports = Behavior(function(){
'use strict';
return {
options: {
'url_route_on': false, //是否开启自定义URL路由
'url_route_rules': [] //自定义URL路由规则
},
run: function(){
if (!this.options.url_route_on) {
return false;
}
var routes = this.options.url_route_rules;
var length = routes.length;
if (length === 0) {
return false;
}
var pathname = this.http.pathname;
var match;
for(var i = 0; i < length; i++){
var route = routes[i];
var rule = route[0];
//正则路由
if (isRegexp(rule)) {
match = pathname.match(rule);
if (match) {
var result = this.parseRegExp(match, route[1], pathname);
if (result) {
return result;
}
}
}else{
//字符串路由
match = this.checkUrlMatch(pathname, rule);
if (match) {
return this.parseRule(rule, route[1], pathname);
}
}
}
return false;
},
/**
* 解析字符串路由
* @param {[type]} rule [description]
* @param {[type]} route [description]
* @param {[type]} pathname [description]
* @return {[type]} [description]
*/
parseRule: function(rule, route, pathname){
route = this.getRoute(route);
if (!route) {
return false;
}
pathname = Dispatcher.splitPathName(pathname);
rule = Dispatcher.splitPathName(rule);
var matches = [];
var self = this;
rule.forEach(function(item){
var pathitem = pathname.shift();
if (item.indexOf(':') === 0) {
if (item.indexOf('\\') === -1) {
self.http.get[item.substr(1)] = pathitem;
}else{
matches.push(pathitem);
}
}
});
//将剩余的pathname分割为querystring
if (pathname.length) {
for(var i = 0,length = Math.ceil(pathname.length)/2; i < length; i++){
this.http.get[pathname[i * 2]] = pathname[i * 2 + 1] || '';
}
}
route = route.replace(/:(\d+)/g, function(a, b){
return matches[b - 1] || '';
});
this.parseUrl(route);
return true;
},
/**
* 检测URL是否匹配
* @param {[type]} pathname [description]
* @param {[type]} rule [description]
* @return {[type]} [description]
*/
checkUrlMatch: function(pathname, rule){
pathname = Dispatcher.splitPathName(pathname);
rule = Dispatcher.splitPathName(rule);
return rule.every(function(item, i){
if (item.indexOf(':') === 0) {
if (item.indexOf('\\') > -1) {
var type = item.substr(-1);
var reg;
switch(type){
case 'd':
reg = /^\d+$/;
break;
case 'w':
reg = /^\w+$/
break;
}
if (reg && !reg.test(pathname[i])) {
return false;
}
}
}else{
var pitem = pathname[i] || '';
if (pitem.toLowerCase() !== item.toLowerCase()) {
return false;
}
}
return true;
});
},
/**
* 解析转化后的url
* @param {[type]} urlInfo [description]
* @return {[type]} [description]
*/
parseUrl: function(urlInfo){
urlInfo = url.parse(urlInfo, true);
if (!isEmpty(urlInfo.query)) {
for(var key in urlInfo.query){
if (urlInfo.query[key] || !(key in this.http.get)) {
this.http.get[key] = urlInfo.query[key];
}
}
}
// 过滤调用pathname最后有/的情况
var pathname = Dispatcher.splitPathName(urlInfo.pathname);
this.http.action = Dispatcher.getAction(pathname.pop());
this.http.controller = Dispatcher.getController(pathname.pop());
this.http.group = Dispatcher.getGroup(pathname.pop());
},
/**
* 获取route
* @param {[type]} route [description]
* @return {[type]} [description]
*/
getRoute: function(route, matches){
if (isObject(route)) {
//对应的请求类型
for(var method in route){
//由于请求类型没有包含关系,这里可以直接用indexOf判断
if (method.toUpperCase().indexOf(this.http.method) > -1) {
return route[method];
}
}
return;
}
var routeUpper = route.toUpperCase();
//RESTFUL API
if (routeUpper === 'RESTFUL' || routeUpper.indexOf('RESTFUL:') === 0) {
var group = route.split(':')[1] || C('restful_group');
route = group + '/' + matches[1] + '/' + this.http.method.toLowerCase() + '?resource=' + matches[1];
if (matches[2]) {
route += '&id=' + matches[2];
}
//设置变量到http对象上,方便后续使用
this.http.isRestful = true;
return route;
}
return route;
},
/**
* 正则匹配路由
* @param {[type]} matches [description]
* @param {[type]} route [description]
* @param {[type]} pathname [description]
* @return {[type]} [description]
*/
parseRegExp: function(matches, route, pathname){
route = this.getRoute(route, matches);
if (!route) {
return false;
}
//替换路由字符串里的:1, :2 匹配都的值
//如:group/detail?date=:1&groupId=:2&page=:3
route = route.replace(/:(\d+)/g, function(a, b){
return matches[b] || '';
});
pathname = pathname.replace(matches[0], '');
pathname = Dispatcher.splitPathName(pathname);
//将剩余的pathname分割为querystring
if (pathname.length) {
for(var i = 0,length = Math.ceil(pathname.length)/2; i < length; i++){
this.http.get[pathname[i * 2]] = pathname[i * 2 + 1] || '';
}
}
this.parseUrl(route);
return true;
}
};
}); |