自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Gracejs : 全新的基于koa2的前后端分離框架

開發(fā) 前端
Gracejs(又稱:koa-grace v2) 是全新的基于koa v2.x的MVC+RESTful架構(gòu)的前后端分離框架。Gracejs完美支持koa v2,同時(shí)做了優(yōu)化虛擬host匹配和路由匹配的性能、還完善了部分測(cè)試用例等諸多升級(jí)。當(dāng)然,如果你正在使用koa-grace也不用擔(dān)心,我們會(huì)把Gracejs中除了支持koa2的性能和功能特性移植到koa-grace的相應(yīng)中間件中。

Gracejs(又稱:koa-grace v2) 是全新的基于koa v2.x的MVC+RESTful架構(gòu)的前后端分離框架。

一、簡(jiǎn)介

Gracejs是koa-grace的升級(jí)版,也可以叫koa-grace v2。

github地址: https://github.com/xiongwilee/koa-grace

主要特性包括:

  1. 支持MVC架構(gòu),可以更便捷地生成服務(wù)端路由;
  2. 標(biāo)準(zhǔn)的RESTful架構(gòu),支持后端接口異步并發(fā),頁面性能更優(yōu);
  3. 一套Node環(huán)境經(jīng)服務(wù)服務(wù)多個(gè)站點(diǎn)應(yīng)用,部署更簡(jiǎn)單;
  4. 優(yōu)雅的MOCK功能,開發(fā)環(huán)境模擬數(shù)據(jù)更流暢;
  5. ***支持async/await及generator語法,隨心所欲;
  6. 更靈活的前端構(gòu)建選型,默認(rèn)支持Vue及Require.js。

相比于koa-grace v1(以下簡(jiǎn)稱:koa-grace):Gracejs***支持koa v2,同時(shí)做了優(yōu)化虛擬host匹配和路由匹配的性能、還完善了部分測(cè)試用例等諸多升級(jí)。當(dāng)然,如果你正在使用koa-grace也不用擔(dān)心,我們會(huì)把Gracejs中除了支持koa2的性能和功能特性移植到koa-grace的相應(yīng)中間件中。

這里不再介紹“前后端分離”、“RESTful”、“MVC”等概念,有興趣可參考趣店前端團(tuán)隊(duì)基于koajs的前后端分離實(shí)踐一文。

二、快速開始

注意:請(qǐng)確保你的運(yùn)行環(huán)境中Nodejs的版本至少是v4.0.0,目前需要依賴Babel。(當(dāng)然26日凌晨nodejs v7已經(jīng)release,你也可以不依賴Babel,直接通過--harmony_async_await模式啟動(dòng)。)

安裝

執(zhí)行命令:

  1. $ git clone -b v2.x https://github.com/xiongwilee/koa-grace.git 
  2.  
  3. $ cd koa-grace && npm install  

運(yùn)行

然后,執(zhí)行命令: 

  1. $ npm run dev 

然后訪問:http://127.0.0.1:3000 就可以看到示例了!

三、案例說明

這里參考 https://github.com/xiongwilee... 中app/demo目錄下的示例,詳解Gracejs的MVC+RESTful架構(gòu)的實(shí)現(xiàn)。

此前也有文章簡(jiǎn)單介紹過koa-grace的實(shí)現(xiàn)( https://github.com/xiongwilee... ),但考慮到Gracejs的差異性,這里再從目錄結(jié)構(gòu)、MVC模型實(shí)現(xiàn)、proxy機(jī)制這三個(gè)關(guān)鍵點(diǎn)做一些比較詳細(xì)的說明。

目錄結(jié)構(gòu)

Gracejs與koa-grace v1.x版本的目錄結(jié)構(gòu)完全一致:

  1. ├── controller 
  2. │   ├── data.js 
  3. │   ├── defaultCtrl.js 
  4. │   └── home.js 
  5. ├── static 
  6. │   ├── css 
  7. │   ├── image 
  8. │   └── js 
  9. └── views 
  10.     └── home.html  

其中:

  • controller用以存放路由及控制器文件
  • static用以存放靜態(tài)文件
  • views用以存放模板文件

需要強(qiáng)調(diào)的是,這個(gè)目錄結(jié)構(gòu)是生產(chǎn)環(huán)境代碼的標(biāo)準(zhǔn)目錄結(jié)構(gòu)。在開發(fā)環(huán)境里你可以任意調(diào)整你的目錄結(jié)構(gòu),只要保證編譯之后的產(chǎn)出文件以這個(gè)路徑輸出即可。

如果你對(duì)這一點(diǎn)仍有疑問,可以參考grace-vue-webpack-boilerplate。

MVC模型實(shí)現(xiàn)

為了滿足更多的使用場(chǎng)景,在Gracejs中加入了簡(jiǎn)單的Mongo數(shù)據(jù)庫的功能。

但準(zhǔn)確的說,前后端的分離的Nodejs框架都是VC架構(gòu),并沒有Model層。因?yàn)榍昂蠖朔蛛x框架不應(yīng)該有任何數(shù)據(jù)庫、SESSION存儲(chǔ)的職能。 

如上圖,具體流程如下:

  • ***步,Nodejs server(也就是Gracejs服務(wù))監(jiān)聽到用戶請(qǐng)求;
  • 第二步,Gracejs的各個(gè)中間件(Middlewares)對(duì)請(qǐng)求上下文進(jìn)行處理;
  • 第三步,根據(jù)當(dāng)前請(qǐng)求的path和method,進(jìn)入對(duì)應(yīng)的Controller;
  • 第四步,通過http請(qǐng)求以proxy的模式向后端獲取數(shù)據(jù);
  • 第五步,拼接數(shù)據(jù),渲染模板。

這里的第四步,proxy機(jī)制,就是Gracejs實(shí)現(xiàn)前后端分離的核心部分。

proxy機(jī)制

以實(shí)現(xiàn)一個(gè)電商應(yīng)用下的“個(gè)人中心”頁面為例。假設(shè)這個(gè)頁面的首屏包括:用戶基本信息模塊、商品及訂單模塊、消息通知模塊。

后端完成服務(wù)化架構(gòu)之后,這三個(gè)模塊可以解耦,拆分成三個(gè)HTTP API接口。這時(shí)候就可以通過Gracejs的this.proxy方法,去后端異步并發(fā)獲取三個(gè)接口的數(shù)據(jù)。

如下圖:

這樣有幾個(gè)好處:

  1. 在Nodejs層(服務(wù)端)異步并發(fā)向后端(服務(wù)端)獲取數(shù)據(jù),可以使HTTP走內(nèi)網(wǎng),性能更優(yōu);
  2. 后端的接口可以同時(shí)提供給客戶端,實(shí)現(xiàn)接口給Web+APP復(fù)用,后端開發(fā)成本更低;
  3. 在Nodejs層獲取數(shù)據(jù)后,直接交給頁面,不管前端用什么技術(shù)棧,可以使首屏體驗(yàn)更佳。

那么,這么做是不是就***了呢?肯定不是:

  1. 后端接口在外網(wǎng)開放之后,如何保證接口安全性?
  2. 如果當(dāng)前頁面請(qǐng)求是GET方法,但我想POST到后端怎么辦?
  3. 我想在Controller層重置post參數(shù)怎么辦?
  4. 后端接口設(shè)置cookie如何帶給瀏覽器?
  5. 經(jīng)過一層Nodejs的代理之后,如何保證SESSION狀態(tài)不丟失?
  6. 如果當(dāng)前請(qǐng)求是一個(gè)file文件流,又該怎么辦呢?...

好消息是,這些問題在proxy中間件中都考慮過了。這里不再一一講解,有興趣可以看koa-grace-proxy的源碼:https://github.com/xiongwilee...

四、詳細(xì)使用手冊(cè)

在看詳細(xì)使用手冊(cè)之前,建議先看一下Gracejs的主文件源碼:https://github.com/xiongwilee... 。

這里不再浪費(fèi)篇幅貼代碼了,其實(shí)想說明的就是:Gracejs是一個(gè)個(gè)關(guān)鍵中間件的集合。

所有中間件都在middleware目錄下,配置由config/main.*.js管理。

關(guān)于配置文件:

  1. 配置文件extend關(guān)系為:config/server.json的merge字段 > config/main.*.js > config.js;
  2. 配置生成后保存在Gracejs下的全局作用域global.config里,方便讀取。

下面介紹幾個(gè)關(guān)鍵中間件的作用和使用方法。

vhost——多站點(diǎn)配置

vhost在這里可以理解為,一個(gè)Gracejs server服務(wù)于幾個(gè)站點(diǎn)。Gracejs支持通過host及host+一級(jí)path兩種方式的映射。所謂的隱射,其實(shí)就是一個(gè)域名(或者一個(gè)域名+一級(jí)path)對(duì)應(yīng)一個(gè)應(yīng)用,一個(gè)應(yīng)用對(duì)應(yīng)一個(gè)目錄。

注意:考慮到正則的性能問題,vhost不會(huì)考慮正則映射。

參考config/main.development.js,可以這么配置vhost:

  1. // vhost配置 
  2. vhost: { 
  3.   '127.0.0.1':'demo'
  4.   '127.0.0.1/test':'demo_test'
  5.   'localhost':'blog'
  6.  

其中,demo,demo_test,blog分別對(duì)應(yīng)app/下的三個(gè)目錄。當(dāng)然你也可以指定目錄路徑,在配置文件中修改path.project配置即可:

  1. // 路徑相關(guān)的配置 
  2. path: { 
  3.   // project 
  4.   project: './app/' 
  5.  

router——路由及控制器

Gracejs中生成路由的方法非常簡(jiǎn)單,以自帶的demo模塊為例,進(jìn)入demo模塊的controller目錄:app/demo/controller。

文件目錄如下:

  1. controller 
  2. ├── data.js 
  3. ├── defaultCtrl.js 
  4. └── home.js  

1、 文件路徑即路由

router中間件會(huì)找到模塊中所有以.js結(jié)尾的文件,根據(jù)文件路徑和module.exports生成路由。

例如,demo模塊中的home.js文件:

  1. exports.index = async function () { 
  2.   await this.bindDefault(); 
  3.   await this.render('home', { 
  4.     title: 'Hello , Grace!' 
  5.   }); 
  6. exports.hello = function(){ 
  7.   this.body = 'hello world!' 
  8.  

則生成/home/index、/home、/home/hello的路由。需要說明幾點(diǎn):

  1. 如果路由是以/index結(jié)尾的話,Gracejs會(huì)"贈(zèng)送"一個(gè)去掉/index的同樣路由;
  2. 如果當(dāng)前文件是一個(gè)依賴,僅僅被其他文件引用;則在文件中配置exports.__controller__ = false,該文件就不會(huì)生成路由了;參考defaultCtrl.js
  3. 這里的控制器函數(shù)可以是await/async或generator函數(shù),也可以是一個(gè)普通的函數(shù);Gracejs中推薦使用await/async;
  4. 這里的路由文件包裹在一個(gè)目錄里也是可以的,可以參考:app/blog中的controller文件;
  5. 如果當(dāng)前文件路由就是一個(gè)獨(dú)立的控制器,則module.exports返回一個(gè)任意函數(shù)即可。

***,如果用戶訪問的路由查找不到,router會(huì)默認(rèn)查找/error/404路由,如果有則渲染error/404頁(不會(huì)重定向到error/404),如果沒有則返回404。

2、 路由文件使用說明

將demo模塊中的home.js擴(kuò)展一下:

  1. exports.index = async function () { 
  2.     ... 
  3. exports.index.__method__ = 'get'
  4. exports.index.__regular__ = null 

另外,需要說明以下幾點(diǎn):

  1. 如果需要配置dashboard/post/list請(qǐng)求為DELETE方法,則post.js中聲明 exports.list.__method__ = 'delete'即可(不聲明默認(rèn)注入get及post方法);
  2. 如果要配置更靈活的路由,則中聲明exports.list.__regular__ = '/:id';即可,更多相關(guān)配置請(qǐng)參看:koa-router#named-routes

當(dāng)然,如果路由文件中的所有控制器方法都是post方法,您可以在控制器文件***部加入:module.exports.__method__ = 'post'即可,__regular__的配置同理。

注意:一般情況這里不需要額外的配置,為了保證代碼美觀,沒有特殊使用場(chǎng)景的話就不要寫__method__和__regular__配置。

3、 控制器

將demo模塊中的home.js的index方法再擴(kuò)展一下:

  1. exports.index = async function () { 
  2.   // 綁定默認(rèn)控制器方法 
  3.   await this.bindDefault(); 
  4.   // 獲取數(shù)據(jù) 
  5.   await this.proxy(...) 
  6.   // 渲染目標(biāo)引擎 
  7.   await this.render('home', { 
  8.     title: 'Hello , Grace!' 
  9.   }); 
  10.  

它就是一個(gè)標(biāo)準(zhǔn)的控制器(controller)了。這個(gè)控制器的作用域就是當(dāng)前koa的context,你可以任意使用koa的context的任意方法。

幾個(gè)關(guān)鍵context屬性的使用說明如下:

koa自帶:

更多koa自帶context屬性,請(qǐng)查看koajs官網(wǎng):http://koajs.com/

context屬性 類型 說明
this.request.href String 當(dāng)前頁面完整URL,也可以簡(jiǎn)寫為this.href
this.request.query object get參數(shù),也可以簡(jiǎn)寫為this.query
this.response.set function 設(shè)置response頭信息,也可以簡(jiǎn)寫為this.set
this.cookies.set function 設(shè)置cookie,參考:cookies
this.cookies.get function 獲取cookie,參考:cookies

Gracejs注入:

context屬性 類型 中間件 說明
this.bindDefault function router 公共控制器,相當(dāng)于require('app/*/controller/defaultCtrl.js')
this.request.body object body post參數(shù),可以直接在this.request.body中獲取到post參數(shù)
this.render function views 模板引擎渲染方法,請(qǐng)參看: 模板引擎- Template engine
this.mongo function mongo 數(shù)據(jù)庫操作方法,請(qǐng)參看: 數(shù)據(jù)庫 - Database
this.mongoMap function mongo 并行數(shù)據(jù)庫多操作方法,請(qǐng)參看: 數(shù)據(jù)庫 - Database
this.proxy function proxy RESTful數(shù)據(jù)請(qǐng)求方法,請(qǐng)參看:數(shù)據(jù)代理
this.fetch function proxy 從服務(wù)器導(dǎo)出文件方法,請(qǐng)參看: 請(qǐng)求代理
this.backData Object proxy 默認(rèn)以O(shè)bejct格式存儲(chǔ)this.proxy后端返回的JSON數(shù)據(jù)
this.upload function xload 文件上傳方法,請(qǐng)參看: 文件上傳下載
this.download function xload 文件下載方法,請(qǐng)參看: 文件上傳下載

4、控制器中異步函數(shù)的寫法

在控制器中,如果還有其他的異步方法,可以通過Promise來實(shí)現(xiàn)。例如:

  1. exports.main = async function() { 
  2.   await ((test) => { 
  3.     return new Promise((resolve, reject) => { 
  4.       setTimeout(() => { resolve(test) }, 3000) 
  5.     }); 
  6.   })('測(cè)試'
  7.  

proxy——數(shù)據(jù)代理

Gracejs支持兩種數(shù)據(jù)代理場(chǎng)景:

  1. 單純的數(shù)據(jù)代理,任意請(qǐng)求到后端接口,然后返回json數(shù)據(jù)(也包括文件流請(qǐng)求到后端,后端返回json數(shù)據(jù));
  2. 文件代理,請(qǐng)求后端接口,返回一個(gè)文件(例如驗(yàn)證碼圖片);

下面逐一介紹兩種代理模式的使用方法。

1、 數(shù)據(jù)代理

數(shù)據(jù)代理可以在控制器中使用this.proxy方法:

  1. this.proxy(object|string,[opt]) 

場(chǎng)景一:多個(gè)數(shù)據(jù)請(qǐng)求的代理

使用this.proxy方法實(shí)現(xiàn)多個(gè)數(shù)據(jù)異步并發(fā)請(qǐng)求非常簡(jiǎn)單:

  1. exports.demo = async function (){ 
  2.   await this.proxy({ 
  3.     userInfo:'github:post:user/login/oauth/access_token?client_id=****'
  4.     otherInfo:'github:other/info?test=test'
  5.   }); 
  6.    
  7.   console.log(this.backData); 
  8.   /** 
  9.    *  { 
  10.    *    userInfo : {...}, 
  11.    *    otherInfo : {...} 
  12.    *  } 
  13.    */ 
  14.  

然后,proxy的結(jié)果會(huì)默認(rèn)注入到上下文的this.backData對(duì)象中。

場(chǎng)景二:?jiǎn)蝹€(gè)數(shù)據(jù)請(qǐng)求的代理

如果只是為了實(shí)現(xiàn)一個(gè)接口請(qǐng)求代理,可以這么寫:

  1. exports.demo = async function (){ 
  2.   await this.proxy('github:post:user/login/oauth/access_token?client_id=****'); 
  3.  

說明

github:post:user/login/oauth/access_token?client_id=****說明如下:

  • github: 為在config/main.*.js的 api 對(duì)象中進(jìn)行配置;
  • post : 為數(shù)據(jù)代理請(qǐng)求的請(qǐng)求方法,該參數(shù)可以不傳,默認(rèn)為get
  • path: 后面請(qǐng)求路徑中的query參數(shù)會(huì)覆蓋當(dāng)前頁面的請(qǐng)求參數(shù)(this.query),將query一同傳到請(qǐng)求的接口
  • 你也可以寫完整的路徑:{userInfo:'https://api.github.com/user/login?test=test'}

另外,this.proxy的形參說明如下:

參數(shù)名 類型 默認(rèn) 說明
dest Object this.backData 指定接收數(shù)據(jù)的對(duì)象,默認(rèn)為this.backData
conf Obejct {} this.proxy使用Request.js實(shí)現(xiàn),此為傳給request的重置配置(你可以在這里設(shè)置接口超時(shí)時(shí)間:conf: { timeout: 25000 }
form Object {} 指定post方法的post數(shù)據(jù),默認(rèn)為當(dāng)前頁面的post數(shù)據(jù)

關(guān)于this.proxy方法還有很多有趣的細(xì)節(jié),推薦有興趣的同學(xué)看源碼:https://github.com/xiongwilee...

2、 文件代理

文件代理可以在控制器中使用this.fetch方法:

  1. this.fetch(string) 

文件請(qǐng)求代理也很簡(jiǎn)單,比如如果需要從github代理一個(gè)圖片請(qǐng)求返回到瀏覽器中,參考:http://feclub.cn/user/avatar?... , 或者要使用導(dǎo)出文件的功能:

  1. exports.avatar = async function (){ 
  2.   await this.fetch(imgUrl); 
  3.  

這里需要注意的是:在this.fetch方法之后會(huì)直接結(jié)束response, 不會(huì)再往其他中間件執(zhí)行。

views——視圖層

默認(rèn)的模板引擎為swig,但swig作者已經(jīng)停止維護(hù);你可以在config/main.*.js中配置template屬性想要的模板引擎:

  1. // 模板引擎配置 
  2. template: 'nunjucks'  

你還可以根據(jù)不同的模塊配置不同的模板引擎:

  1. template: { 
  2.   blog:'ejs' 
  3.  

目前支持的模板引擎列表在這里:consolidate.js#supported-template-engines

在控制器中調(diào)用this.render方法渲染模板引擎:

  1. exports.home = await function () { 
  2.   await this.render('dashboard/site_home',{ 
  3.     breads : ['站點(diǎn)管理','通用'], 
  4.     userInfo: this.userInfo, 
  5.     siteInfo: this.siteInfo 
  6.   }) 
  7.  

模板文件在模塊路徑的/views目錄中。

注意一點(diǎn):Gracejs渲染模板時(shí),默認(rèn)會(huì)將main.*.js中constant配置交給模板數(shù)據(jù);這樣,如果你想在頁面中獲取公共配置(比如:CDN的地址)的話就可以在模板數(shù)據(jù)中的constant子中取到。

static——靜態(tài)文件服務(wù)

靜態(tài)文件的使用非常簡(jiǎn)單,將/static/**/或者/*/static/*的靜態(tài)文件請(qǐng)求代理到了模塊路徑下的/static目錄:

  1. // 配置靜態(tài)文件路由 
  2. app.use(Middles.static(['/static/**/*''/*/static/**/*'], { 
  3.   dir: config_path_project, 
  4.   maxage: config_site.env == 'production' && 60 * 60 * 1000 
  5. }));  

以案例中blog的靜態(tài)文件為例,靜態(tài)文件在blog項(xiàng)目下的路徑為:app/blog/static/image/bg.jpg,則訪問路徑為http://127.0.0.1/blog/static/... 或者 http://127.0.0.1/static/blog/...

注意兩點(diǎn):

  1. 靜態(tài)文件端口和當(dāng)前路由的端口一致,所以/static/**/或者/*/static/*形式的路由會(huì)是無效的;
  2. 推薦在生產(chǎn)環(huán)境中,使用Nginx做靜態(tài)文件服務(wù),購買CDN托管靜態(tài)文件;

mock——Mock數(shù)據(jù)

MOCK功能的實(shí)現(xiàn)其實(shí)非常簡(jiǎn)單,在開發(fā)環(huán)境中你可以很輕易地使用MOCK數(shù)據(jù)。

以demo模塊為例,首先在main.development.js配置文件中添加proxy配置:

  1. // controller中請(qǐng)求各類數(shù)據(jù)前綴和域名的鍵值對(duì) 
  2. api: { 
  3.  // ... 
  4.  demo: 'http://${ip}:${port}/__MOCK__/demo/' 
  5.  // ... 
  6.  

然后,在demo模塊中添加mock文件夾,然后添加test.json:

文件結(jié)構(gòu):

  1. ├── controller 
  2. ├── mock 
  3. |     └── test.json 
  4. ├── static 
  5. └── views  

文件內(nèi)容(就是你想要的請(qǐng)求返回內(nèi)容):

在JSON文件內(nèi)容中也可以使用注釋:

  1. /* 
  2.  * 獲取用戶信息接口 
  3.  */ 
  4.     code:0 // 這是code 
  5.  

然后,你可以打開瀏覽器訪問:http://${ip}:${port}/__MOCK__/demo/test 驗(yàn)證是否已經(jīng)返回了test.json里的數(shù)據(jù)。

***在你的controller業(yè)務(wù)代碼中就可以通過proxy方法獲取mock數(shù)據(jù)了:

  1. this.proxy({ 
  2.     test:'demo:test' 
  3. })  

注意:

  • 如果你的mock文件路徑是/mock/test/subtest.json 那么proxy路徑則是:test/subtest;
  • 強(qiáng)烈建議將mock文件統(tǒng)一為真正的后端請(qǐng)求路徑,這樣以實(shí)現(xiàn)真實(shí)路徑的mock;

可以參考這個(gè):koa-grace中的mock功能的示例

secure——安全模塊

考慮到用戶路由完全由Nodejs托管以后,CSRF的問題也得在Nodejs層去防護(hù)了。此前寫過一片文章:前后端分離架構(gòu)下CSRF防御機(jī)制,這里就只寫使用方法,不再詳述原理。

在Gracejs中可以配置:

  1. // csrf配置 
  2. csrf: { 
  3.   // 需要進(jìn)行xsrf防護(hù)的模塊名稱 
  4.   module: [] 
  5.  

然后,在業(yè)務(wù)代碼中,獲取名為:grace_token的cookie,以post或者get參數(shù)回傳即可。當(dāng)然,如果你不想污染ajax中的參數(shù)對(duì)象,你也可以將這個(gè)cookie值存到x-grace-token頭信息中。

Gracejs監(jiān)聽到post請(qǐng)求,如果token驗(yàn)證失效,則直接返回錯(cuò)誤。

mongo——簡(jiǎn)單的數(shù)據(jù)庫

請(qǐng)注意:不推薦在生產(chǎn)環(huán)境中使用數(shù)據(jù)庫功能

在Gracejs中使用mongoDB非常簡(jiǎn)單,當(dāng)然沒有做過任何壓測(cè),可能存在性能問題。

1、 連接數(shù)據(jù)庫

在配置文件config/main.*.js中進(jìn)行配置:

  1. // mongo配置 
  2.   mongo: { 
  3.     options:{ 
  4.       // mongoose 配置 
  5.     }, 
  6.     api:{ 
  7.       'blog''mongodb://localhost:27017/blog' 
  8.     } 
  9.   },  

其中,mongo.options配置mongo連接池等信息,mongo.api配置站點(diǎn)對(duì)應(yīng)的數(shù)據(jù)庫連接路徑。

值得注意的是,配置好數(shù)據(jù)庫之后,一旦koa-grace server啟動(dòng)mongoose就啟動(dòng)連接,直到koa-grace server關(guān)閉

2、 mongoose的schema配置

依舊以案例blog為例,參看app/blog/model/mongo目錄:

  1. └── mongo 
  2.     ├── Category.js 
  3.     ├── Link.js 
  4.     ├── Post.js 
  5.     └── User.js  

一個(gè)js文件即一個(gè)數(shù)據(jù)庫表即相關(guān)配置,以app/blog/model/mongo/Category.js:

  1. // 表結(jié)構(gòu) 
  2. let schema = [{ 
  3.   id: {type: String,uniquetrue,required: true}, 
  4.   name: {type: String,required: true}, 
  5.   numb: {type: Number,'default':0} 
  6. }, { 
  7.   autoIndex: true
  8.   versionKey: false 
  9. }]; 
  10.  
  11. // 靜態(tài)方法:http://mongoosejs.com/docs/guide.html#statics 
  12. let statics = {} 
  13.  
  14. // 方法擴(kuò)展 http://mongoosejs.com/docs/guide.html#methods 
  15. let methods = { 
  16.   /** 
  17.    * 獲取博客分類列表 
  18.    */ 
  19.   list: function* () { 
  20.     return this.model('Category').find(); 
  21.   } 
  22.  
  23. module.exports.model = model; 
  24. module.exports.schema = schema
  25. module.exports.statics = statics; 
  26. module.exports.methods = methods;  

主要有四個(gè)參數(shù):

  • model , 即表名,***與當(dāng)前文件同名
  • schema , 即mongoose schema
  • methods , 即schema擴(kuò)展方法,推薦把數(shù)據(jù)庫元操作都定義在這個(gè)對(duì)象中
  • statics , 即靜態(tài)操作方法

3、 在控制器中調(diào)用數(shù)據(jù)庫

在控制器中使用非常簡(jiǎn)單,主要通過this.mongo,this.mongoMap兩個(gè)方法。

1) this.mongo(name)

調(diào)用mongoose Entity對(duì)象進(jìn)行數(shù)據(jù)庫CURD操作

參數(shù)說明:

@param [string] name : 在app/blog/model/mongo中配置Schema名,

返回:

@return [object] 一個(gè)實(shí)例化Schema之后的Mongoose Entity對(duì)象,可以通過調(diào)用該對(duì)象的methods進(jìn)行數(shù)據(jù)庫操作

案例

參考上文中的Category.js的配置,以app/blog/controller/dashboard/post.js為例,如果要在博客列表頁中獲取博客分類數(shù)據(jù):

  1. // http://127.0.0.1/dashboard/post/list 
  2. exports.list = async function (){ 
  3.   let cates = await this.mongo('Category').list(); 
  4.   this.body = cates; 
  5.  

2)this.mongoMap(option)

并行多個(gè)數(shù)據(jù)庫操作

參數(shù)說明

@param [array] option

@param [Object] option[].model mongoose Entity對(duì)象,通過this.mongo(model)獲取

@param [function] option[].fun mongoose Entity對(duì)象方法

@param [array] option[].arg mongoose Entity對(duì)象方法參數(shù)

返回

@return [array] 數(shù)據(jù)庫操作結(jié)果,以對(duì)應(yīng)數(shù)組的形式返回

案例

  1. let PostModel = this.mongo('Post'); 
  2.  let mongoResult = await this.mongoMap([{ 
  3.      model: PostModel, 
  4.      fun: PostModel.page, 
  5.      arg: [pageNum] 
  6.    },{ 
  7.      model: PostModel, 
  8.      fun:PostModel.count
  9.      arg: [pageNum] 
  10.    }]); 
  11.  
  12.  let posts = mongoResult[0];// 獲取***個(gè)查詢PostModel.page的結(jié)果 
  13.  let page = mongoResult[1]; // 獲取第二個(gè)查詢PostModel.count的結(jié)果,兩者并發(fā)執(zhí)行  

xload——文件上傳下載

請(qǐng)注意:不推薦在生產(chǎn)環(huán)境中使用文件上傳下載功能

與數(shù)據(jù)庫功能一樣,文件上傳下載功能的使用非常簡(jiǎn)單,但不推薦在生產(chǎn)環(huán)境中使用。因?yàn)槟壳皟H支持在單臺(tái)服務(wù)器上使用數(shù)據(jù)庫功能,如果多臺(tái)機(jī)器的服務(wù)就有問題了。

如果需要在線上使用上傳下載功能,你可以使用proxy的方式pipe到后端接口,或者通過上傳組件直接將文件上傳到后端的接口。

1、文件上傳

方法:

  1. this.upload([opt]) 

示例:

  1. exports.aj_upload = async function() { 
  2.   await this.bindDefault(); 
  3.  
  4.   let files = await this.upload(); 
  5.   let res = {}; 
  6.  
  7.   if (!files || files.length < 1) { 
  8.     res.code = 1; 
  9.     res.message = '上傳文件失?。?
  10.     return this.body = res;  
  11.   } 
  12.  
  13.   res.code = 0; 
  14.   res.message = ''
  15.   res.data = { 
  16.     files: files 
  17.   } 
  18.  
  19.   return this.body = res; 
  20.  

2、文件下載

方法:

  1. this.download(filename, [opt]) 

示例:

  1. exports.download = async function() { 
  2.   await this.download(this.query.file); 

其他

Gracejs中幾個(gè)核心的中間件都介紹完畢。此外,還有幾個(gè)中間件不做詳細(xì)介紹,了解即可:

  1. gzip實(shí)現(xiàn):使用gzip壓縮response中的body;
  2. http body內(nèi)容解析:解析request中的body,存到this.request.body字段中;
  3. 簡(jiǎn)單的session實(shí)現(xiàn):通過內(nèi)存或者redis保存session,不推薦在生產(chǎn)環(huán)境中使用;生產(chǎn)環(huán)境的session服務(wù)由后端自行完成。

***,關(guān)于Gracejs的運(yùn)維部署在這里不再詳述,推薦使用pm2,不用擔(dān)心重啟server期間服務(wù)不可用。

五、前端構(gòu)建

到這里,整個(gè)前后端服務(wù)的搭建都介紹完了。

在介紹如何結(jié)合Gracejs進(jìn)行前端構(gòu)建之前,先提一下:這種“更徹底”的前后端分離方案相比于基于MVVM框架的單頁面應(yīng)用具體有什么不同呢?

個(gè)人認(rèn)為有以下幾點(diǎn):

  • 運(yùn)維部署更靈活

基于Nodejs server的服務(wù)端構(gòu)建,服務(wù)器的部署可以與后端機(jī)器獨(dú)立出來。而且后端同學(xué)就僅僅需要關(guān)注接口的實(shí)現(xiàn)。

  • 前端技術(shù)棧更統(tǒng)一

比如:PHP部署頁面路由,前端通過MVVM框架實(shí)現(xiàn),前端還需要學(xué)習(xí)PHP語法來實(shí)現(xiàn)后端路由。

  • 前端架構(gòu)和選型更便捷

比如你可以很容易通過模板引擎完成BigPipe的架構(gòu),你也可以從內(nèi)網(wǎng)異步并發(fā)獲取首屏數(shù)據(jù)。

當(dāng)然Gracejs是只是服務(wù)端框架,前端架構(gòu)如何選型,隨你所愿。目前已經(jīng)有基于Vue和requirejs的boilerplate。

這里以基于Vue的構(gòu)建為例。

目錄結(jié)構(gòu)

一個(gè)完整的依賴基于vue+Gracejs的目錄結(jié)構(gòu)推薦使用這種模式:

  1. ├── app 
  2. │   └── demo 
  3. │         ├── build 
  4. │         ├── controller 
  5. │         ├── mock 
  6. │         ├── static 
  7. │         ├── views 
  8. │         └── vues 
  9. └── gracejs 
  10.     ├── app 
  11.     │    └── demo 
  12.     ├── middleware 
  13.     ├── ...  

當(dāng)然,Gracejs允許你配置app目錄路徑,你可以放到任意你想要的目錄里。

這里的demo模塊比默認(rèn)的Gracejs下的demo模塊多出來兩個(gè)目錄:build和vues。

構(gòu)建思路

其實(shí),到這里也能猜到如何進(jìn)行構(gòu)建了:build目錄是基于webpack的編譯腳本,vues目錄是所有的.vue的前端業(yè)務(wù)文件。

webpack將vues下的vue文件編譯之后產(chǎn)出到gracejs/app/demo/static下;其他controller等沒有必要編譯的文件,直接使用webpack的復(fù)制插件復(fù)制到gracejs/app/demo/的對(duì)應(yīng)目錄下即可。

有興趣的同學(xué),推薦看grace-vue-webpack-boilerplate下的build實(shí)現(xiàn)源碼;當(dāng)然,需要對(duì)webpack和vue有一定的了解。

歡迎同學(xué)們貢獻(xiàn)基于React、Angular的boilerplate,以郵件或者ISSUE的形式通知我們之后,添加到gracejs的官方文檔中。

結(jié)語

自此,洋洋灑灑1w多字,Gracejs終于介紹完畢;有興趣的同學(xué)去github賞個(gè)star唄:https://github.com/xiongwilee... 。

***,歡迎大家提issue、fork;有任何疑問也可以郵件聯(lián)系:xiongwilee[at]foxmail.com。

責(zé)任編輯:龐桂玉 來源: segmentfault
相關(guān)推薦

2014-04-18 14:43:07

前后端分離NodeJS

2019-06-12 19:00:14

前后端分離AppJava

2023-02-08 16:29:58

前后端開發(fā)

2019-07-09 05:44:35

前后端分離架構(gòu)接口規(guī)范

2014-04-18 10:04:15

NodeJS前后端分離

2018-04-20 16:15:42

Koa2上傳下載

2022-04-06 07:50:57

JWT后端Spring

2022-01-26 07:53:07

koa2后端服務(wù)器

2021-09-18 09:45:33

前端接口架構(gòu)

2022-05-27 10:40:04

前后端權(quán)限控制設(shè)計(jì)

2020-01-14 08:58:38

Serverless框架web

2015-11-12 10:32:27

前端后端分離

2017-02-15 10:18:32

架構(gòu)前后端分離

2021-10-20 18:21:18

項(xiàng)目技術(shù)開發(fā)

2020-09-25 11:50:12

前后端分離架構(gòu)Web

2022-04-07 08:06:32

viteVue3項(xiàng)目

2018-08-23 16:18:59

2014-08-15 10:05:37

Angular權(quán)限控制

2015-07-01 15:32:39

前端前后端分離

2016-08-22 13:31:05

前端架構(gòu)前后端分離
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)