原文連接:BlueSun | 爲何使用Sails?javascript
入手Node.js半年,從用Express開發本身的博客到用Sails開發公司項目,深深被Sails震撼了。Sails是Balderdash團隊的產品,快速的項目構建、優秀的框架結構還有衆多的擴展,讓我有種相見恨晚的感受。在Koa流行以前,我的認爲Sails的用戶量仍是挺可觀的。今天,我想寫一寫Sails那些讓我感動的地方,順便理順一下Sails的架構。前端
一步搭建項目java
項目架構node
ORMgit
MVC的實現github
路由數據庫
安全npm
日誌json
單元測試bootstrap
WebSocket
在安裝了Node.js 和 Sails的環境下,只須要一條命令,就可以搭建一個擁有完整架構的項目,儘管這很簡單,我仍是以爲有必要說一下。
在已經安裝了Node.js和npm的前提下,首先你須要全局下安裝Sails$ sudo npm install sails -g
其次在一個空路徑下,新建一個項目$ sails new newApp
最後,只須要前往項目路徑,把項目運行起來$ cd testProject
$ sails lift
訪問 http://localhost:1337
就能看到一個新的項目
. ├── api │ ├── controllers │ ├── models │ ├── policies │ ├── responses │ └── services ├── views ├── assets ├── config ├── tasks ├── node_modules ├── package.json ├── Gruntfile.js ├── README.md └── app.js
api/
api
目錄下是你要構建應用的核心所在,常說的MVC的設計結構就體如今這裏api/controllers
:控制層,該層是Http請求的入口。Sails官方建議該層只處理請求的轉發和頁面的渲染,具體的邏輯實現應該交給Service層。api/models
:模型層,在Sails中,對於Model採用的是充血模型,除了能夠在模型中定於屬性以外,還能夠定義包含邏輯處理的函數。在Sails中,全部Model均可以全局性訪問。api/policies
:過濾層,該層在Controller層以前對Http請求作處理,在這一層中,能夠定於一些規則來過濾Http請求,好比身份認證什麼的。api/responses
:http響應的方法都放這裏,例如服務器錯誤、請求錯誤、404錯誤等,定義在responses文件夾裏面的方法,都會賦值到controller層的req對象中。api/services
:服務層,該層包含邏輯處理的方法,在Sails中,全部Service均可以全局性訪問。
views/
視圖層,存放視圖模版文件的地方,Sails默認是提供ejs模版引擎的,若是你願意,你能夠換成jade、handlebars或者任何你喜歡的模版引擎。
assets/
資源文件夾,在Sails啓動的時候,會啓動某一個Grunt任務,把assets文件夾裏的內容或壓縮或編譯或複製到根目錄下的.tmp
目錄,這是前端能夠直接經過路由訪問的資源,HTML、JS、CSS以及圖片等靜態資源都放在這裏了。
config/
配置文件夾,在Sails啓動的時候,會加載該文件夾裏的文件,並賦值在全局對象sails.config
中,因此可以在任何一個地方都能用到。在用Sails開發,會常常跟這個文件夾裏的文件打交道,從config的構成很容易知道Sails都提供哪方面的功能。
tasks/
Sails自帶的項目自動化工具是Grunt
,而Grunt的配置和任務註冊都放在這個文件夾裏了。這裏已經提供了一般會用到的CSS編譯、JS壓縮、文件合併,更改檢測等等任務,固然若是沒有本身須要的,還能擴展。
app.js
Sails的啓動文件,不管是$ sails lift
命令或者$ npm start
命令都會運行該文件。
開發了Sails的團隊Balderdash,還開發了一套ORM框架:Waterline。
Waterline在Sails主要的舞臺是在/api/models
目錄裏,在這裏定義的模型文件,在Sails啓動的時候,都要經由Waterline的洗禮。
Waterline 是經過Adapter關聯數據庫的,不一樣的Adapter關聯不一樣的數據庫。
Waterline 能適配絕對部分數據庫,大體分類兩類,一類是官方團隊開發的 Adapter適配的,一類是民間開發者開發的Adapter適配的:
官方支持的:
PostgreSQL
MySQL
MongoDB
Redis
Disk
Memory
民間開發的:
SQLServer
OrientDB
Oracle
Cassandra
關於Waterline的更多信息能夠關注:
github:waterline
github:waterline-docs
在這一段我想不只僅要談論到Model層、View層和Controller層,我認爲還有必要談到Service層、和Policy層。
模型文件定義到/api/models
中,由Waterline驅動,全部model都能全局訪問。Sails提供命令行建立model的命令:$ sails generate model MODEL_NAME
實如今/views
中,除了默認提供的ejs模版引擎以外,還能更換成jade、handlebars等模版引擎
在/api/controller
目錄裏,Sails中提供建立controller的命令:$ sails generate controller CONTROLLER_NAME
。Sails也提供同時建立model和對應的Controller的命令:$ sails generate api API_NAME
。
在/api/services
目錄裏,存放自定義的服務,全部service都可以全局訪問,Sails官方的建議是把邏輯處理都放在該層中,Controller層只作路由的分發和輕邏輯的處理。
在/api/policies
目錄裏,存放自定義的過濾器。該層是一條請求在到達Controller以前根據需求過濾請求的中間層。在/api/policies
目錄中定義的文件,還須要在config/policies.js
文件中爲需求應用到某一過濾器的Action配置。
Sails中要理解路由,首先要記得這個名詞blueprint
,中文翻譯爲:藍圖。我不知道官方是否解釋過爲何要用個單詞,但以個人理解,Sails的blueprint是負責指揮每一條客戶端請求應該分配到服務器端的哪一個Action去,因此叫藍圖吧。
blueprint主要分爲三種:RESTful routes
、Shortcut routes
、Action routes
。
當路徑諸如:/:modelIdentity
或者 /:modelIdentity/:id
的時候,blueprint會根據HTTP的動做(GET、POST、DELETE、PUT等)來分配到相應的Controller下相應的Action來處理。例如一個POST請求/user
會建立一個用戶,一個DELETE請求/user/123
會刪除id
爲123的用戶。
這種路由主要是方便開發,請求的參數能夠直接寫在請求路徑中,例如/user/create?name=joe
會建立一個新的用戶,/user/update/1?name=mike
會更新id
爲1的用戶的名字。shortcut routes在開發環境很便利,可是在生產環境下須要關閉。
這種路由會自動的爲Controller層的每個Action建立一個路由,例如你的Controller層有一個FooController.js
,裏面有一個Actionbar
,那麼請求/foo/bar
就會分配到bar
Action。
固然Sails也會提供自定義的路由,用戶能夠在config/routes.js
和config/polices.js
這兩個配置文件中選擇關閉或者打開blueprint提供的路由,和定義本身的路由。
要確保產品的安全性,要對幾種常見的攻擊和安全策略瞭如指掌,諸如CORS、CSRF、DDOS、XSS等。Sails對於常見的安全策略都有提供支持,且只須要經過相關的配置文件就能夠控制安全策略的等級。深刻探討Web的安全策略,並不在本文的範疇內,往後我會以這個爲題寫一篇文章聊聊Web的安全。
想要了解更多Sails的安全策略能夠看看這裏:sails: security
Sails提供了一個全局對象sails.log
用來處理日誌信息的輸出,日誌是分level的,在config/log.js
中配置日誌輸出的level,而level的做用看下錶:
Priority | level | Log fns visible |
---|---|---|
0 | silent | N/A |
1 | error | .error() |
2 | warn | .warn(), .error() |
3 | debug | .debug(), .warn(), .error() |
4 | info | .info(), .debug(), .warn(), .error() |
5 | verbose | .verbose(), .info(), .debug(), .warn(), .error() |
6 | silly | .silly(), .verbose(), .info(), .debug(), .warn(), .error() |
Sails的日誌管理默認是info層的,既會輸出.info(), .debug(), .warn(), .error()的信息。
Sails使用了mocha進行單元測試,在新建Sails項目的時候,沒有建立單元測試的文件夾,須要本身手動構造單元測試目錄,官方建議的目錄是這樣的:
. ├── api ├── assets ├── ... ├── test │ ├── unit │ │ ├── controllers │ │ │ └── UsersController.test.js │ │ ├── models │ │ │ └── Users.test.js │ │ └── ... │ ├── fixtures │ ├── ... │ ├── bootstrap.test.js │ └── mocha.opts └── views
而我在單元測試經常使用的組合是:mocha、should、supertest、 istanbul
其中should是提供斷言,supertest是用於測試Controller層的時候僞造http請求的,而istanbul則是提供測試代碼覆蓋率的。
關於怎麼在Sails中編寫測試代碼,能夠參考 sails:testing
對於有即時性通信需求的Web應用,咱們會用Socket,Sails也爲這方面提供了支持。在客戶端提供js文件:sails.io.js
,而在服務器端提供全局對象:sails.sockets
。經過這兩個對象,就能夠進行客戶端和服務器端即時性通信的開發了。
Sails默認會啓動WebSocket功能,在客戶端訪問服務器端的時候,會自動嘗試在同域名下鏈接socket。
值得注意的是,這樣會對AngularJS、EmberJS等前端MVVC開發產生一些障礙。
好比進行AngularJS開發的時候,咱們在http://localhost:9000
跑AngularJS項目,而服務器端卻跑在http://localhost:1337
。
當訪問http://localhost:9000
的時候,sails.io.js
會嘗試於當前路徑下進行socket鏈接,也就是http://localhost:9000
,這時會出錯,由於服務器是跑在http://localhost:1337
的。
在開發的時候要解決這樣的問題的時候,咱們只須要在AngularJS這邊引入sails.io.js
以後定義鏈接路徑就好了:
<script src="scripts/lib/sails.io.js"></script> <script>io.sails.url = "http://localhost:1337";</script>
能夠說Sails涵蓋了Web開發中會遇到的絕大部分需求和問題,若是深刻研究Sails的話,是受益不淺的。
若是本文對您有用
請不要吝嗇大家的Follow與Start
這會大大支持咱們繼續創做
「Github」
MZMonster :@MZMonster
JC_Huang :@JerryC8080