thinkjs/lib/Lib/Behavior/CheckRouteBehavior.js
2014-07-30 23:11:02 +08:00

201 lines
6.1 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 检测路由行为
* 通过自定义路由识别到对应的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;
}
};
});