(摘抄官方文檔:https://thinkjs.org/zh-cn/doc/2.2/controller.html)
控制器
控制器是一類操作的集合,用來響應(yīng)用戶同一類的請求。
創(chuàng)建文件 src/home/controller/article.js,表示 home 模塊下有名為 article 控制器,文件內(nèi)容類似如下:
ES6 方式
'use strict';
import Base from './base.js';
export default class extends Base {
/**
* index action
* @return {Promise} []
*/
indexAction(){
//auto render template file index_index.html
return this.display();
}
}
init 方法
ES6 里的 class 有 contructor 方法,但動(dòng)態(tài)創(chuàng)建的類就沒有該方法了,為了統(tǒng)一初始化執(zhí)行的方法,將該方法統(tǒng)一定義為 init。
該方法在類實(shí)例化的時(shí)候自動(dòng)調(diào)用,無需手工調(diào)用。
ES6 方式
'use strict';
import Base from './base.js';
export default class extends Base {
init(http){
super.init(http); //調(diào)用父類的init方法
...
}
}
init 方法里需要調(diào)用父類的 init 方法,并將參數(shù) http 傳遞進(jìn)去。
前置操作 __before
ThinkJS 支持前置操作,方法名為 __before,該方法會(huì)在具體的 Action 調(diào)用之前自動(dòng)調(diào)用。如果前置操作里阻止了后續(xù)代碼繼續(xù)執(zhí)行,則不會(huì)調(diào)用具體的 Action,這樣可以提前結(jié)束請求。
ES6 方式
'use strict';
import Base from './base.js';
export default class extends Base {
/**
* 前置方法
* @return {Promise} []
*/
__before(){
...
}
}
Action
一個(gè) Action 代表一個(gè)要執(zhí)行的操作。如: url 為 /home/article/detail,解析后的模塊為 /home,控制器為 article, Action 為 detail,那么執(zhí)行的 Action 就是文件 src/home/controller/aritcle 里的 detailAction 方法。
'use strict';
import Base from './base.js';
export default class extends Base {
/**
* 獲取詳細(xì)信息
* @return {Promise} []
*/
detailAction(self){
...
}
}
如果解析后的 Action 值里含有 _,會(huì)自動(dòng)做轉(zhuǎn)化,具體的轉(zhuǎn)化策略見 路由 -> 大小寫轉(zhuǎn)化。
后置操作 __after
ThinkJS 支持后置操作,方法名為 __after,該方法會(huì)在具體的 Action 調(diào)用之后執(zhí)行。如果具體的 Action 里阻止了后續(xù)的代碼繼續(xù)執(zhí)行,則后置操作不會(huì)調(diào)用。
空操作 __call
當(dāng)解析后的 url 對(duì)應(yīng)的控制器存在,但 Action 不存在時(shí),會(huì)試圖調(diào)用控制器下的魔術(shù)方法 __call。這里可以對(duì)不存在的方法進(jìn)行統(tǒng)一處理。
'use strict';
import Base from './base.js';
export default class extends Base {
/**
* @return {Promise} []
*/
__call(){
...
}
}
數(shù)據(jù)校驗(yàn)
控制器里在使用用戶提交的數(shù)據(jù)之前,需要對(duì)數(shù)據(jù)合法性進(jìn)行校驗(yàn)。為了降低控制器里的邏輯復(fù)雜度,ThinkJS 提供了一層 Logic 專門用來處理數(shù)據(jù)校驗(yàn)和權(quán)限校驗(yàn)等相關(guān)操作。
詳細(xì)信息請見 擴(kuò)展功能 -> Logic -> 數(shù)據(jù)校驗(yàn)。
http 對(duì)象
控制器在實(shí)例化時(shí),會(huì)將 http 傳遞進(jìn)去。該 http 對(duì)象是 ThinkJS 對(duì) req 和 res 重新包裝的一個(gè)對(duì)象,而非 Node.js 內(nèi)置的 http 對(duì)象。
Action 里如果想獲取該對(duì)象,可以通過 this.http 來獲取。
'use strict';
import Base from './base.js';
export default class extends Base {
indexAction(){
let http = this.http;
}
}
關(guān)于 http對(duì)象包含的屬性和方法請見 API -> http。
this 作用域的問題
Node.js 里經(jīng)常有很多異步操作,而異步操作常見的處理方式是使用回調(diào)函數(shù)或者 Promise。這些處理方式都會(huì)增加一層作用域,導(dǎo)致在回調(diào)函數(shù)內(nèi)無法直接使用 this,簡單的處理辦法是在頂部定義一個(gè)變量,將 this 賦值給這個(gè)變量,然后在回調(diào)函數(shù)內(nèi)使用這個(gè)變量。如:
module.exports = think.controller({
indexAction: function(){
var self = this; //這里將 this 賦值給變量 self,然后在后面的回調(diào)函數(shù)里都使用 self
this.model('user').find().then(function(data){
return self.model('article').where({user_id: data.id}).select();
}).then(function(data){
self.success(data);
})
}
})
如果每個(gè) Action 里都要使用者手工寫一個(gè) var self = this,勢必比較麻煩。為了解決這個(gè)問題,ThinkJS 在 Action 里直接提供了一個(gè)參數(shù),這個(gè)參數(shù)等同于 var self = this,具體如下:
module.exports = think.controller({
//參數(shù) self 等同于 var self = this
indexAction: function(self){
this.model('user').find().then(function(data){
return self.model('article').where({user_id: data.id}).select();
}).then(function(data){
self.success(data);
})
}
})
JSON 輸出
項(xiàng)目中經(jīng)常要提供一些接口,這些接口一般都是直接輸出 JSON 格式的數(shù)據(jù),并且會(huì)有標(biāo)識(shí)表明當(dāng)前接口是否正常。如果發(fā)生異常,需要將對(duì)應(yīng)的錯(cuò)誤信息隨著接口一起輸出??刂破骼锾峁┝?this.success 和 this.fail 方法來輸出這樣的接口數(shù)據(jù)。
1.輸出正常的 JSON
可以通過 this.success 方法輸出正常的接口數(shù)據(jù),如:
export default class extends think.controller.base {
indexAction(){
let data = {name: "thinkjs"};
this.success(data);
}
}
輸出結(jié)果為 {errno: 0, errmsg: "", data: {"name": "thinkjs"}},客戶端可以通過 errno 是否為 0 來判斷當(dāng)前接口是否有異常。
2.輸出含有錯(cuò)誤信息的 JSON
可以通過 this.fail 方法輸出含有錯(cuò)誤信息的接口數(shù)據(jù),如:
export default class extends think.controller.base {
indexAction(){
this.fail(1000, 'connect error'); //指定錯(cuò)誤號(hào)和錯(cuò)誤信息
}
}
輸出結(jié)果為 {errno: 1000, errmsg: "connect error"},客戶端判斷 errno 大于 0,就知道當(dāng)前接口有異常,并且通過 errmsg 拿到具體的錯(cuò)誤信息。
3.配置錯(cuò)誤號(hào)和錯(cuò)誤信息
如果每個(gè)地方輸出錯(cuò)誤的時(shí)候都要指定錯(cuò)誤號(hào)和錯(cuò)誤信息勢必比較麻煩,比較好的方式是把錯(cuò)誤號(hào)和錯(cuò)誤信息在一個(gè)地方配置,然后輸出的時(shí)候只要指定錯(cuò)誤號(hào),錯(cuò)誤信息根據(jù)錯(cuò)誤號(hào)自動(dòng)讀取。
錯(cuò)誤信息支持國際化,所以配置放在 src/common/config/locale/[lang].js 文件中。如:
export default {
10001: 'get data error'
}
通過上面的配置后,執(zhí)行 this.fail(10001) 時(shí)會(huì)自動(dòng)讀取到對(duì)應(yīng)的錯(cuò)誤信息。
4.友好的錯(cuò)誤號(hào)
在程序里執(zhí)行 this.fail(10001) 雖然能輸出正確的錯(cuò)誤號(hào)和錯(cuò)誤信息,但人不能直觀的看出來錯(cuò)誤號(hào)對(duì)應(yīng)的錯(cuò)誤信息是什么。
這時(shí)可以將 key 配置為大寫字符串,值為錯(cuò)誤號(hào)和錯(cuò)誤信息。如:
export default {
GET_DATA_ERROR: [1234, 'get data error'] //key 必須為大寫字符或者下劃線才有效
}
執(zhí)行 this.fail('GET_DATA_ERROR') 時(shí)也會(huì)自動(dòng)取到對(duì)應(yīng)的錯(cuò)誤號(hào)和錯(cuò)誤信息。
常用功能
1.獲取 GET 參數(shù)
可以通過 get 方法獲取 GET 參數(shù),如:
export default class extends think.controller.base {
indexAction(){
let name = this.get("name");
let allParams = this.get(); //獲取所有 GET 參數(shù)
}
}
如果參數(shù)不存在,那么值為空字符串。
2.獲取 POST 參數(shù)
可以通過 post 方法獲取 POST 參數(shù),如:
export default class extends think.controller.base {
indexAction(){
let name = this.post('name');
let allParams = this.post(); //獲取所有 POST 參數(shù)
}
}
如果參數(shù)不存在,那么值為空字符串。
3.獲取上傳的文件
可以通過 file 方法獲取上傳的文件,如:
export default class extends think.controller.base {
indexAction(){
let file = this.file('image');
let allFiles = this.file(); //獲取所有上傳的文件
}
}
返回值是個(gè)對(duì)象,包含下面的屬性:
{
fieldName: 'file', //表單字段名稱
originalFilename: filename, //原始的文件名
path: filepath, //文件保存的臨時(shí)路徑,使用時(shí)需要將其移動(dòng)到項(xiàng)目里的目錄,否則請求結(jié)束時(shí)會(huì)被刪除
size: 1000 //文件大小
}
如果文件不存在,那么值為一個(gè)空對(duì)象 {}。
更多方法
isGet() 當(dāng)前是否是 GET 請求
isPost() 當(dāng)前是否是 POST 請求
isAjax() 是否是 AJAX 請求
ip() 獲取請求用戶的 ip
redirect(url) 跳轉(zhuǎn)到一個(gè) url
write(data) 輸出數(shù)據(jù),會(huì)自動(dòng)調(diào)用 JSON.stringify
end(data) 結(jié)束當(dāng)前的 http 請求
json(data) 輸出 JSON 數(shù)據(jù),自動(dòng)發(fā)送 JSON 相關(guān)的 Content-Type
jsonp(data) 輸出 JSONP 數(shù)據(jù),請求參數(shù)名默認(rèn)為 callback
success(data) 輸出一個(gè)正常的 JSON 數(shù)據(jù),數(shù)據(jù)格式為 {errno: 0, errmsg: "", data: data}
fail(errno, errmsg, data) 輸出一個(gè)錯(cuò)誤的 JSON 數(shù)據(jù),數(shù)據(jù)格式為 {errno: errno_value, errmsg: string, data: data}
download(file) 下載文件
assign(name, value) 設(shè)置模版變量
display() 輸出一個(gè)模版
fetch() 渲染模版并獲取內(nèi)容
cookie(name, value) 獲取或者設(shè)置 cookie
session(name, value) 獲取或者設(shè)置 session
header(name, value) 獲取或者設(shè)置 header
action(name, data) 調(diào)用其他 Controller 的方法,可以跨模塊
model(name, options) 獲取模型實(shí)例