UNPKG

node-framework

Version:

node-framework

156 lines (131 loc) 9.81 kB
# controllers 控制器(controllers)是web应用的核心,用以处理各种http请求。控制器内部由一个或多个行为(action)构成,每个action即为web应用对外暴露的最小单元。用户通过输入URL,经过route的路由映射到特定的controlleraction,从而完成特定的处理后返回相应的内容。 不同于[express](https://github.com/strongloop/express)框架,node-framework的controller独立于route之外,是单独包装成的类。controllers目录中的每个文件均为一个controller。单个文件内部的每个exports的方法或对象均为一个action。 ## 使用方法 因为默认路由配置中已经包含了如下基础路由规则: ```javascript // 默认路由配置规则 '/:controller/:action/:id((\\d+))': { controller: '{controller}', action: '{action}' }, '/:controller/:action': { controller: '{controller}', action: '{action}' }, '/:controller': { controller: '{controller}' } ``` 因此当用户访问`host:port/myController/myAction`时,不需额外配置或者注册,系统会自动调用controllers/myController.js中exports的名为'myAction'的方法或对象。下面将主要关注controller的编写方式,有关路由设置规则请参见[这里](/config#routes) controller共有两种编写方式,对象方式用以处理较为简单的应用场景;类方式因为拥有构造函数从而能够在其内部创建共用变量或逻辑,因此常用于处理略微复杂的应用场景。 ### 对象方式 对象方式要求controller.js内部直接exports一个对象。该对象的key为action的名字;value为处理方法,接受两个参数,分别为request对象和response对象。通过调用response对象的`send``redirect``render`等方法返回响应,完成一次请求。示例代码如下: ```javascript // 对象方式编写的示例controller文件:controller/api.js module.exports = { // 正常响应 normal: function (req, res) { res.send('normal'); }, // 报错响应 error: function (req, res) { setTimeout( function () { throw new Error(); }, 20 ) }, // 长时间响应 responseWarning: function (req, res) { setTimeout( function () { res.send('response in 1000ms'); }, 1000 ); } }; ``` ### 类方式 类方式要求controller.js内部创建并exports一个类。这个类必须继承`require('node-framework').Controller`,并且必须在构造函数第一句调用`Controller.apply(this, Array.prototype.slice.call(arguments, 0));`。创建的类的每个原型方法为一个action。这个方法并不接受参数,但是在内部可以通过调用`this.req``this.res`来获取request和response对象。这种编写方式在多个action需要共用同一个变量时推荐使用,如下述示例中共用`monitorModel`的情况。 ```javascript // node-monitor模块controller/api.js,因为共用monitorModel,所以采用类方式编写。 var util = require('util'); var Controller = require('node-framework').Controller; var MonitorModel = require('../model/Monitor'); function ApiController() { // 必须位于构造函数第一句 Controller.apply(this, Array.prototype.slice.call(arguments, 0)); // 创建共用变量 this.monitorModel = new MonitorModel(this.app); } // 必须继承node-framework提供的Controller基类 util.inherits(ApiController, Controller); // 创建action ApiController.prototype.actionStats = function () { // 调用共用变量monitorModel的方法 var def = this.monitorModel.insert('stats', { id: body.appid, appkey: body.appkey }, insertObj); def.then(function () { me.res.send('success'); }, function (err) { console.log(err); me.res.send('fail'); }); }; // 创建第二个action ApiController.prototype.actionStatus = function () { // 调用共用变量monitorModel的方法 this.monitorModel.insert('status', { id: body.appid, appkey: body.appkey }, { appid: body.appid, timestamp: body.timestamp, data: body.data, host: body.host }).then(function () { me.res.send('success'); }, function (err) { console.log('actionStatus error occured!\n'); console.log(err); me.res.send('fail'); }); }; ``` ## API 虽然node-framework并非基于express,但其内部实现和包装使得request和response对象基本等价于express框架的req和res。这里简单列出request对象和response对象包含的常用信息,以供参考,更详细的信息也可参见[express API](http://expressjs.com/api.html) ### request对象包含属性如下: 名称 | 类型 | 使用示例 | 说明 -----|------|----------|------ path | string(@CLASS=type type-string) | `req.path` | 返回请求地址,例如用户输入`example.com:3000/users?sorc=desc`,返回`'/users'` hostname | string(@CLASS=type type-string) | `req.hostname` | 返回请求域名,不带端口号。例如用户输入`example.com:3000/users?sorc=desc`,返回`'example.com'` cookies | object(@CLASS=type type-object) | `req.cookies` | 获取所有cookie,返回的对象key为cookie具体字段的名字,value为cookie值。如要获取具体某项字段的值,也可以直接使用`requrest.cookies.someKey`。 ip | string(@CLASS=type type-string) | `req.ip` | 返回请求者IP地址 xhr | boolean(@CLASS=type type-boolean) | `req.xhr` | 返回是否为xhr请求。内部是通过检查`req.header('X-Requested-With') === 'XMLHttpRequest'`实现的。 ### request对象包含方法如下: 名称 | 参数类型 | 返回值类型 | 使用示例 | 说明 -----|----------|------------|----------|------ param | string(@CLASS=type type-string) | string(@CLASS=type type-string) | `req.param('key')` | 获取请求附带的参数,获取顺序按照params(URL上?之后的参数),body(POST的参数),query(路由规则中:后的参数)。如果不包含该参数返回`undefined` get | string(@CLASS=type type-string) | string(@CLASS=type type-string) | `req.get('referrer')` | 获取请求头特定字段的信息 header | string(@CLASS=type type-string) | string(@CLASS=type type-string) | `req.header('referrer')` | 同`get` accepts | string(@CLASS=type type-string) | string(@CLASS=type type-string) | `req.accepts(‘text/html')` | 检查输入参数的类型是否被接受。如果接受返回最佳接受的类型,否则返回`undefined`。 is | string(@CLASS=type type-string) | boolean(@CLASS=type type-boolean) | `req.is('text/html')` | 检查请求是否包含`Content-Type`字段并且是否匹配输入参数的类型。 ### response对象包含方法或属性如下: 名称 | 参数类型 | 返回值类型 | 使用示例 | 说明 -----|----------|------------|----------|------ render | string(@CLASS=type type-string)\[object\](@CLASS=type type-object) | void(@CLASS=type) | `res.render('some/view', (@BR){key1: 'value1', key2: 'value2'});` | 选择某个前端模板进行渲染并作为响应输出。前端模板的基准地址在`config/global.js``templateDir`字段。 redirect | \[number\](@CLASS=type type-number)string(@CLASS=type type-string) | void(@CLASS=type) | `res.redirect(301, '/other/path');` | 将响应重定向到某个地址,可以是站内地址也可以是站外地址。第一个参数表示HTTP状态码(例如301),该参数可选。 send | string(@CLASS=type type-string) | void(@CLASS=type) | `res.send('Hello World!');` | 发送指定字符串作为HTTP响应。参数也可以是字符流或者对象,详情参见[express API](http://expressjs.com/api.html#response)。 json | object(@CLASS=type type-object) | void(@CLASS=type) | `res.json({message: 'Hello World!'});` | 发送指定对象以JSON格式作为HTTP响应。 jsonp | object(@CLASS=type type-object) | void(@CLASS=type) | `res.jsonp({message: 'Hello World!'});` | 发送一个jsonp响应。该响应会根据URL参数中`callback`字段的值作为方法名,并将参数对象作为方法参数响应。例如用户访问`/info?callback=sayHi`,示例方法会响应`sayHi({message: 'Hello World!'})`(@BR)jsonp的方法名称字段名可以在`config/server.js`中的`jsonpCallback`配置项更改,默认为`'callback'` sendFile | string(@CLASS=type type-string) | void(@CLASS=type) | `res.sendFile('/path/to/file');` | 将文件内容读取出来并写入响应。内部使用[send](https://github.com/visionmedia/send#options)。更多信息也可参见[express API](http://expressjs.com/api.html#response)。 end | - | void(@CLASS=type) | `res.end();` | 不发送任何数据直接关闭连接,避免因超时而抛错。 status | number(@CLASS=type type-number) | object(@CLASS=type type-object) | `res.status(400)` | 设置HTTP状态码,返回response本身,因此可以继续链式调用,如`res.status(404).send('Not Found!');`。 set | string(@CLASS=type type-string)string(@CLASS=type type-string) | void(@CLASS=type) | `res.set('Content-Type', 'text/plain')` | 设置响应头信息。也可以将一个对象传入作为唯一参数,对象的key为响应头字段,value为响应头的值。 get | string(@CLASS=type type-string) | string(@CLASS=type type-string) | `res.get('Content-Type')` | 获取响应头信息。 cookie | string(@CLASS=type type-string)string(@CLASS=type type-string)\[object\](@CLASS=type type-object) | void(@CLASS=type) | `res.cookie('rememberme', '1', (@BR){(@BR)httpOnly: true, (@BR)expires: new Date(Date.now() + 900000)(@BR)})` | 设置用户cookie,其他options参数可参见[express API](http://expressjs.com/api.html#response)。