写在前面
到目前为止,项目的结构还十分简单。路由的请求直接写在了它的回调函数中。今天笔者要给项目添加控制器模块,封装处理请求的逻辑;为了应对Nodejs的异步请求模型中的大量回调函数,笔者将采取when.js来处理,通过一个实际的手机号开户地查询接口案例展开。话不多说,我们现在开始~
关于when.js的介绍,请参考下面这篇文章:http://blog.csdn.net/hellobeifeng/article/details/46831767
controllers
在项目根目录下创建controllers文件夹,在controllers目录下创建index.js文件作为模块对外入口,同时在controllers/目录下创建website.js文件作为处理服务器首页的一些基本路由请求的控制器文件
index.js文件如下
website.js文件如下,仅仅是一个简单的页面渲染
在index.js文件内引入路由及其对应的控制器模块
运行程序
到目前为止我们已经可以把处理请求的逻辑封装到了单独的文件内,这样我们就可以把处理不同路由请求的处理函数封装到controllers/的任何一个文件内。但是仅仅能渲染静态页面的网站并不能叫做完整的网站,我们来做点特别的事情,通过封装services模块,模拟请求一个开源的求手机号开户所在地的接口。
services
安装依赖
我么需要http.js/underscore.js/request.js/when.js一系列类库,请各位一一安装。这一系列组合拳,是为了将 nodejs中request请求的callback方式改为经典的promise方式
根目录下创建config.js文件
这个config文件主要是用来区分dev staging production三中环境用的,分别使用不同的对象可以切换到不同的接口地址。但是本文中暂时还没有对着三中环境进行区分,所以笔者现在config文件中生命了一个taobao对象,config[taobao]意味着请求httpUrl对应的接口地址。
接口介绍
http://tcc.taobao.com/cc/json/mobile_tel_sagment.html?tel=18888888888,接口就会返回给我们一个json对象,包括开户地,运营商等
__GetZoneResult_ = {
mts:'1888888',
province:'北京',
catName:'中国移动',
telString:'18888888888',
areaVid:'29400',
ispVid:'3236139',
carrier:'北京移动'
}
我们要做的就是用nodejs模拟这个过程
引入控制器
修改入口文件中的路由 index.js,引入controllers/中新增的处理手机号查询的控制器phoneNumInfo.js
编辑控制器
编辑phone.js文件 文件向外导出一个phoneNumInfo对象。这个对象接收一个请求中带来的query值,作为调用接口的手机号字段tel ,调用services/模块中的phone.js的info函数,这个函数中封装了对接口的请求
注意这里使用了when,js的promise模型,phone.info(tel)后面采用链式拼接的.then(function(result){})用来接收services/返回的对象.如果某个控制器里同时需要对多个接口进行调用的话,可以如下使用
var firstPromise = interface1.info();
var secondPromise = inferface2.info();
when.all([firstPromise, secondPromise])
.then(function(result){
var one = result[0].data;
var two = result[1].data;
还有,别忘了在controllers/index.js中添加新的引用 var phone = require('./phone.js');
创建services/phone.js文件
接口肯定需要一个url和参数,这里的phone.js文件从config文件中获取domain(httpUrl),加上从控制器传来的tel参数,拼成一个完整的URL,调用http.getJson(url)函数,发起请求。(注,上文说过,其实没必要弄一个config.js文件,因为不区分环境同时也只调用这个域名下的接口一次的话完全可以把url完整的写在services/phone,js中,只从controllers中获取tel参数)
services目录下创建http.js代码如下
/**
* 封装request请求,将callback方式改为promise的方式
* options参数参考request库
* https://github.com/request/request
*/
var when = require('when');
var request = require('request');
var _ = require('underscore');
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var http = {
/**
* 默认选项
* @param options
* @param method
* @returns {*|{}}
*/
getOptions:function(options,method){
var result = options || {};
if(_.isString(options)){
result = {
uri:options,
method:method,
timeout:15000
};
}
result.uri = encodeURI(result.uri);
if(result.uri.indexOf('https') >= 0){
result.agentOptions = {
secureProtocol: 'SSLv3_method'
}
}
result.method = method;
result.timeout = 15000;
return result;
},
/**
* 请求入口,封装Promise调用
* @param options 参考:https://github.com/request/request#requestoptions-callback
* @returns {*}
*/
request:function(options){
var deferred = when.defer();
var resolver = deferred.resolver;
request(options,function(err,response,body){
if(!err && response.statusCode == 200){
resolver.resolve(body);
}else{
resolver.reject(err);
}
});
return deferred.promise;
},
/**
* get suger方法
* @returns {*} request promise
*/
get:function(options){
options = this.getOptions(options,'GET');
return this.request(options);
},
/**
* get json suger方法
* @returns {*} request promise
*/
getJson:function(options){
return this.get(options).then(function(body){
return JSON.parse(body);
});
},
/**
* post suger方法
* @returns {*} request promise
*/
post:function(options,form){
options = this.getOptions(options,'POST');
options.form = form;
return this.request(options);
},
/**
* post json suger方法
* @returns {*} request promise
*/
postJson:function(options,form){
return this.post(options,form).then(function(body){
return JSON.parse(body);
});
}
};
module.exports = http;
查看运行成果
本节,我们实现了如下功能,封装路由的逻辑请求形成controllers/模块,封装services/模块完成对一个开源接口的调用,并取回接口的传参。从而实现了类似于MVC的分离(虽然不是标准的)。下一篇博客我将会介绍如何在项目中继承mongodb数据库及其建模工具mongoose第三方库
白了个白~