mirror of
https://github.com/thinkjs/thinkjs.git
synced 2026-01-25 14:42:47 +00:00
218 lines
6.5 KiB
JavaScript
218 lines
6.5 KiB
JavaScript
/**
|
||
* 检测路由行为
|
||
* 通过自定义路由识别到对应的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;
|
||
},
|
||
/**
|
||
* 分割pathname
|
||
* @param {[type]} pathname [description]
|
||
* @return {[type]} [description]
|
||
*/
|
||
split: function(pathname){
|
||
var ret = [];
|
||
var j = 0;
|
||
pathname = pathname.split('/');
|
||
for(var i = 0, length = pathname.length, item; i < length; i++){
|
||
item = pathname[i].trim();
|
||
if (item) {
|
||
ret[j++] = item;
|
||
}
|
||
}
|
||
return ret;
|
||
},
|
||
/**
|
||
* 解析字符串路由
|
||
* @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 = this.split(pathname);
|
||
rule = this.split(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 = this.split(pathname);
|
||
rule = this.split(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 = this.split(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 = this.split(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;
|
||
}
|
||
};
|
||
}); |