Sail.js官方文件閱讀筆記(二)——api/controllers/ 目錄
Sails專案結構中api包包含了後端的主要邏輯。其中包含了多個主要目錄:
2.1 api/controllers/
此目錄中的js檔案包含了與models的互動邏輯與向客戶端渲染檢視。
2.1.1 總述
Actions是Sails應用中用來處理web請求的主要物件。
Actions和應用中的routes繫結,當用戶請求一個URL時,被繫結的action會執行邏輯和響應。
2.1.2 actions樣例
actions檔案有兩種形式:classic和actions2。
2.1.2.1 classic形式
傳統的方法新建一個action就是像函式一樣宣告。當客戶端請求一個繫結路徑的action時,此方法會形成一個請求物件作為第一個引數,形成一個響應物件作為第二個引數。如下是一個例子,通過id找使用者,或者展示歡迎介面,如果使用者找不到會轉到登入介面。
module.exports = async function welcomeUser (req, res) { // Get the `userId` parameter from the request. // This could have been set on the querystring, in // the request body, or as part of the URL used to // make the request. var userId = req.param('userId'); // If no `userId` was specified, or it wasn't a number, return an error. if (!_.isNumeric(userId)) { return res.badRequest(new Error('No user ID specified!')); } // Look up the user whose ID was specified in the request. var user = await User.findOne({ id: userId }); // If no user was found, redirect to signup. if (!user) { return res.redirect('/signup' ); // Display the welcome view, setting the view variable // named "name" to the value of the user's name. return res.view('welcome', {name: user.name}); }
2.1.2.2 actions2形式
與Sails helpers的工作方式類似,通過一種描述性定義來定義actions,它本質上是自文件化與自驗證性。例子如下:
module.exports = { friendlyName: 'Welcome user', description: 'Look up the specified user and welcome them, or redirect to a signup page if no user was found.', inputs: { userId: { description: 'The ID of the user to look up.', // By declaring a numeric example, Sails will automatically respond with `res.badRequest` // if the `userId` parameter is not a number. type: 'number', // By making the `userId` parameter required, Sails will automatically respond with // `res.badRequest` if it's left out. required: true } }, exits: { success: { responseType: 'view', viewTemplatePath: 'pages/welcome' }, notFound: { description: 'No user with the specified ID was found in the database.', responseType: 'notFound' } }, fn: async function (inputs, exits) { // Look up the user whose ID was specified in the request. // Note that we don't have to validate that `userId` is a number; // the machine runner does this for us and returns `badRequest` // if validation fails. var user = await User.findOne({ id: inputs.userId }); // If no user was found, respond "notFound" (like calling `res.notFound()`) if (!user) { return exits.notFound(); } // Display the welcome view. return exits.success({name: user.name}); } };
使用傳統的res,req方法可以減少程式碼量,但actions2有以下好處:
1. 程式碼不會直接依賴res和req,使其可以更好的複用和抽象入helpers。
2. 可以迅速決定action需要的請求引數的名字和型別,而且在action執行之前可以自動驗證。
3. 可以不用分析程式碼而看到執行action所有可能的結果。
在一個容器中,程式碼可以標準化,使之可以更容易複用和修改。因為可以首先宣告action的引數,可以更少可能暴露底部用例和安全漏洞。
2.1.2.3 退出標誌
在一個action,helper或指令碼中,預設丟擲任何東西都會引發錯誤返回。如果想要其他的返回,就必須丟擲一些特殊的標誌。比如:
return exits.hasConflictingCourses();
throw 'hasConflictingCourses';
throw { hasConflictingCourses: ['CS 301', 'M 402'] };
除了便於記憶,退出標誌在迴圈等結構中特別有用,但是仍想以一種特殊的方式退出。
2.1.3 controllers
編寫Sails應用最快的方法就是把各類操作都組織在controller檔案中。其檔名必須以Controller結尾,包含一組操作。例如:
module.exports = {
login: function (req, res) { ... },
logout: function (req, res) { ... },
signup: function (req, res) { ... },
};
2.1.4 獨立操作檔案
對於大型應用,使用獨立的操作檔案會更好。這種形式與所有操作都在一個controller檔案中相比,每個操作都在api/controller目錄下有獨立的檔案。例如:
api/
controllers/
user/
login.js
logout.js
signup.js
每個js檔案都有一個包含req,res的方法或一個actions定義。
這種模式有幾種優勢:
1. 更容易追蹤應用中的動作,只要看檔案目錄即可,無須檢視程式碼。
2. 每個操作檔案都很小,比較容易維護,而controller檔案可能隨著應用複雜變大。
3. 針對操作檔案的路由更直觀。
4. 可以為高階操作設計目錄路由,可以用一個api/controller/index.js來繫結應用的 / 路由。
2.1.5 保持精簡
在MVC框架的傳統設計中,Sails應用的controller通常很簡單,因為可複用的程式碼都在helper中。這樣做可以在應用變得複雜時使程式碼更容易維護。但是,過早的把程式碼都移動到helper會引發一些維護問題,影響效率。
建議在使用到重複程式碼三次及以上時,將其移動到helper中進行復用。
2.2 api/models/
此目錄包含應用中的資料結構。
2.3 api/policies
此目錄中包含了js檔案本質上是express中介軟體為了對應用中controllers行為進行驗證。