分享一個基於 Node.js 的 Web 開發框架 – Nokitjs

Houfeng發表於2015-12-06

簡介

Nokit 是一個簡單易用的基於 Nodejs 的 Web 開發框架,預設提供了 MVC / NSP / RESTful 等支援,並提供對應專案模板、管理工具。

資源

安裝和更新

安裝 nokit

[sudo] npm install nokitjs [-g]

更新 nokit

[sudo] npm update nokitjs [-g]

命令列工具

使用 “命令列工具” 時必須全域性安裝 nokitjs (全域性安裝的同時也可以在 app 中本地安裝 nokitjs),Nokit 應用只需在磁碟建立應用目錄,並新建相關檔案和目錄即可, Nokit 提供了方便的命令列工具。

命令列工具還提供了程式管理相關功能,確保應用能夠持續穩定的執行,並能在遇到故障時快速自動恢復。

檢視版本

[sudo] nokit [?]

建立應用

[sudo] nokit create [name] [mvc|nsp|restful] [folder] 

以上命令會生成一個最簡單的應用所需要的目錄結構和配置。

  1. name 一般不建議省略(省略時為 nokit-app),name 將會作為應用的根目錄名稱

  2. type 預設為 mvc 也可以指定為 nsp 或 restful ,指定型別後將會建立對應的應用模板

  3. folder 為目標目錄,省略時將預設為當前所在目錄。

執行應用

[sudo] nokit start [port] [root] [-env:<name>] [-cluster[:num]] [-watch[:.ext,...]] [node-opts]
  1. -env 指定執行配置名稱,將會根據 “配置名稱” 載入 app.xxx.json (xxx 為指定的配置名稱) 作為應用配置檔案。

  2. -cluster 選項可以開啟 “單機叢集模式”,使應用有效的利用多核 CPU,也使應用更加健壯可靠,-cluster 選項可以指定程式數,如 -cluster:4 ,預設為 CPU 核數。

  3. -watch 選項開啟後,在應用檔案發生改變時會自動完成程式重啟,預設任何檔案變更都將觸發重啟,也可以指定檔案型別,如 -watch:.js,.html,.css

  4. -public 一般用於為 html/js/css 等靜態資源啟動一個臨時 WebServer,指定靜態資源目錄,靜態資源目錄為 root 的相對目錄。

  5. -cache 一般用於為 html/js/css 等靜態資源啟動一個臨時 WebServer,指定快取配置,例如 -cache:0 不向瀏覽器傳送快取 header 資訊。

  6. –debug 為 nodejs 選項,可以開啟 debug 模式,開啟後可以使用 nodejs 內建除錯工具調式,也可以使用 node-inspector 等工具進行除錯。

停止應用

[sudo] nokit stop [pid|all]

可以指定 pid (程式ID,可以用過 nokit list 檢視),停止指定的的應用,也可以省略停止所有應用

重啟應用

[sudo] nokit restart [pid|all]

可以指定 pid (程式ID,可以用過 nokit list 檢視),重啟指定的的應用,也可以省略重啟所有應用

檢視執行中的應用

[sudo] nokit list

檢視所有已啟動的應用

開機自啟動

[sudo] nokit autostart [on|off] [-uid:[domain]user [-pwd:password]] 

autostart 命令目前支援 win32 和 linux 平臺,此命令需要管理員許可權,如 ubuntu 需要使用 sodu
在 windows 平臺會彈出 “使用者賬戶控制” 提示框。
-uid 和 -pwd 引數僅在 win32 平臺有效,其它平臺將被忽略,在不指定 -uid 、-pwd 引數時,需有使用者登入到 windows
才會自動啟動 Nokit App,當指定 -uid、-pwd 時,只要啟動 windows 就會自動啟動 Nokit App。
無論是登入 windows 的賬戶或是通過 -uid 提定的賬戶,需要是安裝 nodejs 和 npm 時所用的賬戶。

在程式碼中引用

除了使用命令列工具,也可以在程式碼中引用 nokit 的方式來執行 nokit 應用,
在程式碼中引用 nokit,將不能利用 nokit 的程式管理功能,這時可以直接執行,或者使用 pm2、forever 等工具進行管理。

var nokit = require("nokitjs");
var server = new nokit.Server({
    root : "應用根目錄",
    port : 8000
});
server.start();

無論任種方式,啟動成功後,即可瀏覽器訪問 “http://localhost:8000” (埠請換成具體應用的正確的埠),
示例站點 http://jser.cc (還未全部開發完畢)

NSP

NSP 全稱為 Nokit Server Pages 是一種類似 asp / asp.net 的 Web 應用開發模式,
NSP 支援 include 引用其它頁面,也支援 master 母板頁 技術。

一般目錄結構

根目錄
│ app.json
│ app.js
├─layout
│     date.nsp
│     master.nsp
├─model
└─public
    │  index.nsp
    │  index.nsp.js
    └─style
         common.css

NSP 頁面 (*.nsp) 基本介紹

輸出內容

<p> <%= "輸出內容" %> </p>
<!-- this 指向頁面處理器,無處理器頁面指向預設處理器物件 -->
<p> <%= this.context.request.formData("name") %> </p>

迴圈

<ul> 
<% $.each(this.list,function(i,item){ %>
    <li><%= item.name %></li>
<% }) %>
</ul>

分支

<% if(this.type==`a`){ %>
<span>a</span>
<% }else{ %>
<span>b</span>
<% } %>

包含

<% $.include("../layout/head.nsp") %>

母板頁(Master Page)

<html>
...
<div> <% $.placeHolder("content1") %> </div>
...
<div> <% $.placeHolder("content2") %> </div>
...
</html>

內容頁(Content Page)

<% $.master("./master.nsp") %>

<% $.placeBegin("content1") %>
<span>content1</span>
<% $.placeEnd() %>

<% $.placeBegin("content2") %>
<span>content2</span>
<% $.placeEnd() %>

NSP 頁面處理器 (*.nsp.js) 基本介紹

//定義頁面處理器型別
var IndexPresenter = module.exports = function() {};

//初始化方法,每次回發都將觸發 init 方法
IndexPresenter.prototype.init = function() {
    var self = this;
    /*
    self.server //當前 server 例項
    self.context //當前請上下文物件
    self.request //同 context.request,請求物件
    self.response //同 context.response 響應物件
    self.context.request.queryData[`name`] 可以獲取 queryString 對應資料
    self.context.request.formData[`name`] 可以獲取 post 資料
    self.context.data("name") 可以獲取客戶端傳過來的 queryString 或 formData
    self.context.request.cookie 獲取來自客戶的 cookie
    self.context.respone.cookie 向客戶端傳送 cookie
    se軒.context.session 訪問 session 資料
    */
    self.name = `Nokit NSP`;
    //init(初始化)完成後,需要呼叫 ready 方法,通知初始化完成
    self.ready();
};

//預設方法,首次開啟頁面,會觸發 load 方法
IndexPresenter.prototype.load = function() {
    var self = this;
    //由於 nokit 為非同步處理,呼叫 self.render() 方法向瀏覽器呈現頁面.
    //不要在 init 方法呼叫 self.render() 
    self.render();
};

//事件方法,可以繫結到頁面中的 html 控制元件
IndexPresenter.prototype.add = function() {
    var self = this;
    var val = parseInt(self.numBox.val());
    self.numBox.val(++val);
    self.numBox.css("border","solid 1px red");
    self.render();
};

頁面繫結

<!-- 繫結到處理器方法 -->
<input type="button" onclick="nsp.call(`add`)" value=`add` />

共享元素,將普通 DOM 元素通過 “nsp-id” 宣告為客戶端和服務端的共享元素,便可以在客戶端和服務端同時操作指定元素,
並能在回發時保持狀態,類似 Asp.NET 的 WebForms,但理念、原理又非常不同,NSP 共享元素非常輕量,更簡潔易用。

<!-- 此元素可以在服務端和客戶端同時訪問 -->
<input type="text" value="hello" nsp-id=`test` />
Index.prototype.add = function() {
    var self = this;
    //服務端提供類 jQuery 的元素操作 API (相容部分常用 jQUery API)
    self.test.val(`你好`); 
    self.render();
};

MVC

Nokit MVC 是一種設計簡約、符合 MVC 模式 Web 應用開發模式。

一般目錄結構

根目錄
│ app.json
│ app.js
├─controllers
│    home.js
├─models
├─public
│  └─style
│       common.css
└─views
     date.html
     home.html
     master.html

views 目錄存放的是檢視,檢視和 NSP 的頁面相似,支援 include 和 master,語法也完全相同,
不同的是在 mvc 的檢視中 this 指向的是模型,檢視具有單一的責職 ,就是呈現模型中的資料。

controllers 是控制器目錄,單個檔案為一個控制器,用來響應接受來自使用者的請求,並傳遞給模型,
然後,完成模型和檢視的裝配。
models 為模型目錄,nokit 對模型沒有統一的要求和控制,應用的業務邏輯應在模型中完成。

MVC 的控制器示例

//定義控制器型別
var HomeController = module.exports = function() {};

/*
預設 action ,
通常使用者直接請求某一 url 會被路由到指定 controller 的預設 action
*/
HomeController.prototype.index = function() {
    var self = this;
    
    /*
    self.context 可以訪問當前請求上下文物件
    self.context.routeData["name"] 可以獲取路由資料
    self.context.request.queryData[`name`] 可以獲取 queryString 對應資料
    self.context.request.formData[`name`] 可以獲取 post 資料
    self.context.data("name") 可以獲取客戶端傳過來的 queryString 或 formData
    self.context.request.cookie 獲取來自客戶的 cookie
    self.context.respone.cookie 向客戶端傳送 cookie
    se軒.context.session 訪問 session 資料
    */
    
    //通過 self.render 方法呈現指定的檢視,並進行模型繫結
    self.render("home.html", {
        "name": "Nokit MVC"
    });
};

MVC 的 app.json 配置

{
    /*
    配置 handler ,將指定的請求交由 MVC Handler 處理,支援正規表示式,
    如示例,將應用的所有請求都交由 MVC 處理,
    在找不到匹配的路由配置時,會轉由 Static Handler 處理
    */
    "handlers": {
        "^/": "$./handlers/mvc"
    },
    "mvc": {
        /*
        配置 MVC 相關程式碼檔案的存放目錄,指定 controller 和 view 的目錄位置,
        model 不用配置。
        */
        "paths": {
            "controller": "./controllers",
            "view": "./views"
        },
        /*
        每一個路由至少需要指定 pattern(URL匹配模式) 和 target(目標contrller)
        還可以通過配置 action 項指定對應的 action (controller方法)。
        pattern 格式示例 "/user/{userId}" 其中 userId 是佔位符變數,
        可以在 controller 中通過 context.routeData[`userId`] 獲取。
        */
        "routes": [{
            "pattern": "/home",
            "target": "./home.js"
        },{
            "pattern": "/",
            "target": "./home.js"
        }]
    }
}

RESTful

Nokit 用來開發 RESTful Service 是非常方便和簡單的,通過簡潔的 URL 路由配置,抽象出和資源對應的請求處理程式檔案即可,
可以在處理程式中,根據需求實現 get / post / put 等 HttpMethod 即可。

一般目錄結構

根目錄
│ app.json
│ app.js
├─public
│  │  index.nsp
│  └─style
│       common.css
└─restful
      user.js

REST 的資源控制器示例

//定義資源控制器型別,通常一個資源型別視為一個控制器
function HelloController() {};

/**
 * post 處理方法
 **/
HelloController.prototype.post = function () {
    var self = this;
    /*
    self.context 可以訪問當前請求上下文物件
    self.context.routeData["name"] 可以獲取路由資料
    self.context.request.queryData[`name`] 可以獲取 queryString 對應資料
    self.context.request.formData[`name`] 可以獲取 post 資料
    self.context.data("name") 可以獲取客戶端傳過來的 queryString 或 formData
    self.context.request.body 可以訪問請求的主體物件
    */
    self.out({
        "status": "success",
        "message": "Hello " + self.context.routeData["name"] + "!"
    });
};

/**
 * get 處理方法
 **/
HelloController.prototype.get = function () {
    var self = this;
    self.out({
        "status": "success",
        "message": "Hello " + self.context.routeData["name"] + "!"
    });
};

REST 的 app.json 配置

{
    /*
    配置 handler ,將指定的請求交由 REST Handler 處理,支援正規表示式,
    如示例,/api/... 開頭的請求,交由 REST Handler 處理
    */
    "handlers": {
        "^/api/": "$./handlers/restful"
    },
    "restful": {
        "path": "./restful", //指定資源控制器的存放目錄
        /*
        每一個路由至少需要指定 pattern(URL匹配模式) 和 target(目標contrller)
        pattern 格式示例 "/user/{userId}" 其中 userId 是佔位符變數,
        REST 的路由配置沒有 action 配置項。
        */
        "routes": [{
             "pattern": "/api/hello/{name}",
             "target": "./hello"
        }]
    }
}

Filter

Filter 可以在請求的不同階段截獲請求,進行相關邏輯處理後,繼續向下處理請求或結束請求,一個完整的 filter 包括 4 個事件,如下

//定義一個 Filter
function DemoFilter(){}

//在請求開始時
DemoFilter.prototype.onRequestBegin = function (context, next) {
    next();
};

//在收到資料時
DemoFilter.prototype.onReceived = function (context, next) {
    next();
};

//在向客戶端響應內容時
DemoFilter.prototype.onResponse = function (context, next) {
    next();
};

//在請求即將結束時
DemoFilter.prototype.onRequestEnd = function (context, next) {
    next();
};

在應用中註冊 Filter,在 應用配置 app.json 中配置:

{
    "filters":{
        "^/":"./filters/demo-filter.js"
    }
}

相關文章