nodejs REST 轻量级框架

作者 : solq

blog : http://www.cnblogs.com/solq/p/3574640.html

整个框架只有一个核心文件,两个配置文件,够轻了吧

1.只需要添加  ws Controller 文件就行,启动自动注入 Controller

2.path 路径参数,请求参数自动注入

3.请求参数格式转换,可扩展转换类型

 

先晒晒代码

config.js

/**
 * @author solq
 * @deprecated blog: cnblogs.com/solq
 * */
var appConfig={
    /**db config**/
    dbHost : ‘127.0.0.1‘,
    dbPort : 9977 , 
    dbUser : ‘‘,
    dbPasssWord : ‘‘,
    
    /**debug config**/
    LOGDEBUG : 1,
    LOGINFO : 2,
    LOGERROR : 4,
    LOGLEVEL : (1 | 4),
    
    /**web config**/    
    webPort : 5555,
    scanController : {
        ‘./ws‘ : {
            //include : [],
            exclude : [‘./ws/test/test1.js‘]
        }
    }
};

module.exports  = appConfig;

debug.js

/**
 * @author solq
 * @deprecated blog: cnblogs.com/solq
 * */
var appConfig = require(‘../config.js‘);
module.exports = {
    debug : function(){
        (appConfig.LOGDEBUG & appConfig.LOGLEVEL) &&
        console.log.apply(console, arguments);        
     },
    error : function(){
        (appConfig.LOGERROR & appConfig.LOGLEVEL) &&
        console.error.apply(console, arguments);
    },
    info : function(){
        (appConfig.LOGINFO & appConfig.LOGLEVEL) &&
        console.info.apply(console, arguments);
    }
}
        
View Code

主入口

app.js

/**
 * @author solq
 * @deprecated blog: cnblogs.com/solq
 * */
var http = require("http"),
    fs = require("fs"),
     appConfig = require(‘./config.js‘),
    debug = require(‘./core/debug.js‘).debug,
    requestController = require(‘./core/RequestController.js‘),
    AppContext={};


//scan Controller
//cp google
var walk = function(dir) {
    var results = []
    var list = fs.readdirSync(dir)
    list.forEach(function(file) {
        file = dir + ‘/‘ + file
        var stat = fs.statSync(file)
        if (stat && stat.isDirectory()) results = results.concat(walk(file))
        else results.push(file)
    })
    return results
}
debug( "register controller : =============================================");
for(var dir in appConfig.scanController){
    var files = walk(dir),
        obj = appConfig.scanController[dir];
    
    for(var i in files){
        var filePath=files[i];
        
        if(obj.include!=null){
            if(obj.include.indexOf(filePath)<0){
                continue;
            }
        }
        
        if(obj.exclude!=null){
            if(obj.exclude.indexOf(filePath)>-1){
                continue;
            }
        }
        
        var controller=require(filePath);
        controller.filePath = filePath ; 
        requestController.add(controller);
        debug( "register controller : ", filePath);
    }
}
debug( "end register controller : =========================================");

http.createServer(function(request, response,AppContext) {

    var result=null;
    try{
         result=requestController.filter(request, response,AppContext);
    }catch(e){    
        response.writeHead(500, {"Content-Type": "text/plain;charset=utf-8"});
        response.write(e);
        response.end();
        return;
    }
    
    response.writeHead(200, {"Content-Type": "text/plain;charset=utf-8"});

    if(result!=null){
    
        if(typeof result == ‘string‘){
            response.write(result);
        }else if(typeof result == ‘object‘ 
            || Array.isArray(result)
        ){
            try{
                response.write(JSON.stringify(result));
            }catch(e){
                response.write(e);
            }            
        }else{
            response.write(result);
        }
        
    }
    
    response.end();
 
  
}).listen(appConfig.webPort);
View Code

ws Controller js

/**
 * @author solq
 * @deprecated blog: cnblogs.com/solq
 * */
module.exports = {    
    ‘/testpath‘:{
        auth : [],//权限
        methods : [‘GET‘,‘POST‘],
        controller : function(request, response){
            console.log("testpath",arguments);
        }
    },
    ‘/testpath/{p1}/{p2}‘:{
        auth : [],//权限
        methods : [‘GET‘],
        controller : function(path_p2,path_p1){
            console.log("testpath==",arguments);
        }
    },
    ‘/testparam‘:{
        auth : [],//权限
        methods : [‘GET‘],
        controller : function(param_p2,param_p1,body_xxx){
            console.log("testparam==",arguments);
        }
    },
    ‘/testpathParam/{p1}/{p2}‘:{
        auth : [],//权限
        methods : [‘GET‘],
        controller : function(path_int_p2,path_p1,param_p1,param_p2){
            console.log("testpathParam",arguments);
        }
    },

    ‘/index‘:{
        auth : [],//权限
        methods : [‘GET‘],
        controller : function(){
            console.log("hello controller");            
            return {‘code‘:200,data:{‘xx‘:‘测试中文‘}};
        }
    }
};

core js

/**
 * @author solq
 * @deprecated blog: cnblogs.com/solq
 * */
var queryUrl = require("url"),
    queryString = require( "querystring" )
    debug = require(‘../core/debug.js‘).debug,
    _error = require(‘../core/debug.js‘).error,
    dateConverter = require(‘../core/dateConverter.js‘);

var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; 

var requestController={
    _urlData : {},
    _pathData : {},
    _paramData : {},
    _pathParamData : {},
    /**
    保存方法参数元数据结构
    {
        sawName : 原始的参数名
        name :  参数名
        index : 参数下标
        type : 参数类型 如 string array int date object
        pathIndex : 对应路径参数下标
        mapType : 映身处理的类型 如 path param body other
        required : 是否注入 默认都为 true 
    }
    */
    getParamMetadata : function(params,url){
        //path 处理
        if(url.lastIndexOf(‘/‘) == url.length){
            url =  url.substring(0, url.length - 1).trim();
        }
         var checkPath = url.replace(/{([^}]+)}/gm,function(a,b,c){
             return ‘{}‘;
        });
        var checkGroup = checkPath.split("/").filter(function(e){return e}),
            sawGroup = url.split("/").filter(function(e){return e});
        
        var result = {
             pathParamData : {},
            paramData : {},
            otherData : {},
            bodyData : null,
            pathParamLength : 0,
            paramLength : 0,
            checkParamLength : 0,
            otherLength : 0 ,
            sawPath : url ,
            checkPath : checkPath,
            sawGroup : sawGroup,
            checkGroup : checkGroup
        };
        if(checkPath != url){
            var checkPathGroup={};
            for(var t in checkGroup){
                var __v=checkGroup[t];
                if(‘{‘==__v[0]){
                    continue;
                }
                
                checkPathGroup[t]= __v;
            }
            result.checkPathGroup = checkPathGroup;
        }
        var injectionkey = [‘path_‘,‘param_‘,‘body_‘,‘def_‘,‘auto_‘,‘int_‘,‘date_‘,‘array_‘,‘object_‘];
        var otherKey =[‘req‘,‘res‘,‘request‘, ‘response‘,‘auto_‘];
        for(var i in params){
            var param = params[i],
                name = param;
                metadata = {
                    sawName : param,
                    index : i,
                    type : ‘string‘,
                    required : true
                };
            
            for(var j in injectionkey){
                name=name.replace(injectionkey[j],‘‘);
            }
            
            metadata.name = name;
            
            if(result[name]!=null)
                _error(‘ParamMetadata register is Has: ‘,param, url);
            
            //参数类型处理            
            if(param.indexOf(‘date_‘)>-1){
                metadata.type = ‘date‘;
            }else if(param.indexOf(‘object_‘)>-1){
                metadata.type = ‘object‘;
            }else if(param.indexOf(‘array_‘)>-1){
                metadata.type = ‘array‘;
            }else if(param.indexOf(‘int_‘)>-1){
                metadata.type = ‘int‘;
            }
            //还有其它等等可扩展
            
            //映射类型处理
            
            if(otherKey.indexOf(param)>-1){
                metadata.mapType = ‘other‘;
                result.otherLength++;
                if(result.otherData[name]!=null)
                    _error(‘ParamMetadata register is Has: ‘,param, url);                    
                
                result.otherData[name] = metadata;
                continue;
            }
            
            if(param.indexOf(‘path_‘)>-1){
                metadata.mapType = ‘path‘;
                result.pathParamLength++;
                if(result.pathParamData[name]!=null)
                    _error(‘ParamMetadata register is Has: ‘,param, url);
                    
                var checkKey=‘{‘+name+‘}‘;
                var gi=sawGroup.indexOf(checkKey);
                if(gi<-1)
                    _error(‘ParamMetadata register path key not find: ‘,param, url , checkKey, sawGroup);
                    
                metadata.pathIndex = gi;
                result.pathParamData[name] = metadata;
                
                continue;
            }

            if(param.indexOf(‘param_‘)>-1){
                metadata.mapType = ‘param‘;
                result.paramLength++;
                
                if(param.indexOf(‘def_‘)<0){
                     result.checkParamLength++;
                    metadata.required=false;
                 }
                if(result.paramData[name]!=null)
                    _error(‘ParamMetadata register is Has: ‘,param, url);
                
                result.paramData[name] = metadata;

                continue;
            }        
            
            if(param.indexOf(‘body_‘)>-1){
                metadata.mapType = ‘body‘;
                if(result.bodyData!=null)
                    _error(‘ParamMetadata register is Has: ‘,param, url);
                result.bodyData = metadata;
                continue;
            }
        }
 
        return result;
    },
    //public function
    add : function(handle){
    
        /***
            1 url 映射处理
            2 参数处理
            3 注入外部上下文
        */
        for(var url in handle){
            var obj = handle[url] ; 
            if(obj.methods==null || obj.methods.length==0){
                obj.methods = [‘GET‘];                
            }            
             for(var i in obj.methods){
                var method = obj.methods[i];                                
                var controller = obj.controller;
                var params = this.getParamNames(controller);
                var paramsMetadata = this.getParamMetadata(params,url);
                var key = this.getKey(method,url);    
                
                obj.paramsMetadata = paramsMetadata;
                
                //分类保存,只要是方便映射,更快处理请求                
                if(paramsMetadata.pathParamLength==0 && paramsMetadata.paramLength==0){ //没有任何路径,请求参数
                    this.injectionUrlMap(key,obj);
                }else if(paramsMetadata.pathParamLength!=0 && paramsMetadata.paramLength==0){ //只有路径 参数
                    
                    key = this.getKey(method,paramsMetadata.checkPath);
                    var groupNum = paramsMetadata.sawGroup.length;
                    this.injectionPathMap(groupNum,key,obj);
                }else if(paramsMetadata.pathParamLength==0 && paramsMetadata.paramLength!=0){ //只有参数                    
                    this.injectionParamMap(key,obj);
                }else if(paramsMetadata.pathParamLength!=0 && paramsMetadata.paramLength!=0){ //都有
                     key = this.getKey(method,paramsMetadata.checkPath);
                    var groupNum = paramsMetadata.sawGroup.length;
                    this.injectionPathAndParamMap(groupNum,key,obj);
                }
         
                //debug("params=====",params,"url=====",url,"paramsMetadata=====",paramsMetadata);        
            }            
                    
        }        
     },
    findPathFilter : function(data,groupPath){
        var _ar = data[groupPath.length];
        
        if(_ar==null) return null;
        var _filter =null;    
         //debug("findPathFilter======", data,groupPath);
        //debug("findPathFilter======", _ar);
        for(var i in _ar){
            var _f = _ar[i];
            var paramsMetadata = _f.paramsMetadata,
                flag = true,
                checkPathGroup = paramsMetadata.checkPathGroup;
                
            
            for(var j in checkPathGroup){
                var checkValue = checkPathGroup[j];
                if( checkValue != groupPath[j] ){
                    flag = false;
                    break;
                }
            }
            //debug("findPathFilter======", checkPathGroup,groupPath,flag);

            if(flag){
                _filter = _f;
                break;
            }
        }
         
        return _filter;
    },
    filter : function(request, response,AppContext){
        
        var _url = request.url;
        if( _url == ‘/favicon.ico‘){
            return;
        }
          
        var method = request.method    ,
            urlObj = queryUrl.parse(_url),
            path = urlObj.pathname.trim(),
             queryObj = queryString.parse( urlObj.query );
        
        if(path.lastIndexOf(‘/‘) == path.length){
            path =  path.substring(0, path.length - 1);
        }
        var paramLength = this.getMapSize(queryObj);
        var key=this.getKey(method,path),
            groupPath = path.split("/").filter(function(e){return e}) ;
        //TODO
        //auth check        
    
        // urlData>pathData>paramData>pathParamData
        var _filter=null,
            isCheckParamLength = false;
        if(paramLength==0){            
            _filter=this._urlData[key];             
            if(_filter==null ){                
                _filter = this.findPathFilter(this._pathData,groupPath);
            }
 
        }else{ 
            isCheckParamLength = true;
            _filter=this._paramData[key];
            if(_filter==null ){
                _filter = this.findPathFilter(this._pathData,groupPath);
            }
 
            if(_filter==null ){
                _filter = this.findPathFilter(this._pathParamData,groupPath);
             }            
        }        
        
        if(_filter==null ){
            _error(‘not find controller : ‘ ,key);            
            return;
        } 
        
        var paramsMetadata = _filter.paramsMetadata,
            _paramLength = paramsMetadata.paramLength,
            _checkParamLength = paramsMetadata.checkParamLength,
            controller = _filter.controller;
        
        if( isCheckParamLength && _paramLength!=paramLength){
            //if(_checkParamLength!=paramLength){ //暂时不支持默认参数
                //TODO throw
                _error(‘paramLength length is wrong : ‘ ,key,‘ name : ‘,paramsMetadata.name,‘ length : ‘,_paramLength,paramLength);
                return;
            //}                    
        }            
        //param length is right            
        //injection path
        //injection param
        //injection paramAndPath
        //injection other
 
        var callParams=[],
            resultMap = {} ;
         
        for(var name in paramsMetadata.pathParamData){
            var metadata = paramsMetadata.pathParamData[name];
            this.injectionParamProcess(request, response,AppContext,metadata,queryObj,groupPath,resultMap);
        }
        
        //paramData
        for(var name in paramsMetadata.paramData){
            var metadata = paramsMetadata.paramData[name];
            this.injectionParamProcess(request, response,AppContext,metadata,queryObj,null,resultMap);                    
        }
        
        //bodyData
        if(paramsMetadata.bodyData!=null){
            this.injectionParamProcess(request, response,AppContext,paramsMetadata.bodyData,queryObj,null,resultMap);    
        }
        //otherData            
        for(var name in paramsMetadata.otherData){
            var metadata = paramsMetadata.otherData[name];
            this.injectionParamProcess(request, response,AppContext,metadata,queryObj,null,resultMap);                    
        }
        
        //sort
        for(var k in resultMap){
            callParams.push(k);
        }
        for(var i in callParams){
            callParams[i]=resultMap[i];
        }
        
        //debug(‘callParams ==============‘,callParams);
        return controller.apply(controller,callParams);
                 
    },
    
    
     //private function    
    injectionParamProcess : function(request, response,AppContext,metadata,queryObj,groupPath,resultMap){
        var index = metadata.index,
            name = metadata.name,
            type = metadata.type,
            mapType = metadata.mapType,
            required = metadata.required,
            value=null;
        switch(mapType){
            case ‘param‘ :
                value = queryObj[name];
                if(value==null && required){
                    //TODO throw
                    _error(‘injectionParam parram is null : ‘,name);
                }
            break;
            case ‘path‘ : 
                var pathIndex = metadata.pathIndex;
                value = groupPath[pathIndex];                
                if(value==null){
                    //TODO throw
                    _error(‘injectionParam path is null : ‘,name);
                }
            break;
            case ‘body‘ :
                value = queryObj;
            break;
            case ‘other‘ :
                //debug(value," other value +++++++++++");
                var otherKey ={‘req‘:request,‘res‘:response,‘request‘:request, ‘response‘:response};
                value = otherKey[name];
            break;
        }
        if(value!=null ){
            switch(mapType){
                case ‘path‘ :
                case ‘param‘ :
                
                    switch(type){
                        case ‘int‘ :
                            var _v=parseInt(value);                            
                            if(isNaN(_v) ){
                                //TODO throw
                                _error(‘injectionParam parram num is null : ‘,name,value);
                            }
                            value=_v;
                        break;
                        case ‘array‘ :                     
                            if(!Array.isArray(value)){
                                value=[value];
                            }                     
                        break;
                        case ‘date‘ :                             
                            value=dateConverter.convert(value);
                        break;
                    }
                break;
            }
        }
        
        
        resultMap[index] = value;             
    },
    injectionPathAndParamMap : function(groupNum,key,controller){
        if(this._pathParamData[groupNum]==null){
            this._pathParamData[groupNum] = {};
        }
        this._pathParamData[groupNum][key]!=null
        && _error("重复注册 REST injectionPathAndParamMap 处理器 : " ,key);
        debug("injectionPathAndParamMap : ",key);
        this._pathParamData[groupNum][key]=controller;
    },
    injectionPathMap : function(groupNum,key,controller){
        if(this._pathData[groupNum]==null){
            this._pathData[groupNum] = {};
        }
        this._pathData[groupNum][key]!=null
        && _error("重复注册 REST injectionPathMap 处理器 : " ,key);
        debug("injectionPathMap : ",key);

        this._pathData[groupNum][key]=controller;
    },
    injectionUrlMap : function(key,controller){
        this._urlData[key]!=null
        && _error("重复注册 REST injectionUrlMap 处理器 : " ,key);
        debug("injectionUrlMap : ",key);

        this._urlData[key]=controller;
    },
    injectionParamMap : function(key,controller){
        this._paramData[key]!=null
        && _error("重复注册 REST injectionParamMap 处理器 : " ,key);
        debug("injectionParamMap : ",key);

        this._paramData[key]=controller;
    },     
    getMapSize : function(map){
        var num=0;
        for(var i in map) num++;
        return num;
    },
    //cp google
    getParamNames : function(func) {
        var fnStr = func.toString().replace(STRIP_COMMENTS, ‘‘)
        var result = fnStr.slice(fnStr.indexOf(‘(‘)+1, fnStr.indexOf(‘)‘)).match(/([^\s,]+)/g)
        if(result === null)
         result = []
        return result
    },
    getKey : function(method,url){
         if(url.lastIndexOf(‘/‘) == url.length){
            url =  key.substring(0, url.length - 1);
        }
        return method.toLowerCase().trim() + "_"+ url.toLowerCase().trim();        
    },
};

module.exports = requestController;
View Code

nodejs REST 轻量级框架,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。