Web框架express
Express 是一個簡潔而靈活的 node.js Web應用框架,提供了豐富的HTTP工具以及來自Connect框架的中介軟體。還附帶一個叫做express的命令列工具,可以用它生成一個kickstart程式。可以用npm的全域性安裝命令(L系需要root許可權,加sudo):
npm install -g express
安裝完在任何目錄下都可以執行express命令,express --help
可以檢視其幫助:
Usage: express [options] [dir]
Options:
-h, --help output usage information
-V, --version output the version number
-s, --sessions add session support
-e, --ejs add ejs engine support (defaults to jade)
-J, --jshtml add jshtml engine support (defaults to jade)
-H, --hogan add hogan.js engine support
-c, --css <engine> add stylesheet <engine> support (less|stylus) (defaults to plain css)
-f, --force force on non-empty directory
在用express生成kickstart程式之前,先express -V
看看我的版本:
3.3.8
一行命令生成kickstart程式:
express -s -c less nodecoffee
於是:
create : nodecoffee
create : nodecoffee/package.json
create : nodecoffee/app.js
create : nodecoffee/public
create : nodecoffee/public/javascripts
create : nodecoffee/public/images
create : nodecoffee/public/stylesheets
create : nodecoffee/public/stylesheets/style.less
create : nodecoffee/routes
create : nodecoffee/routes/index.js
create : nodecoffee/routes/user.js
create : nodecoffee/views
create : nodecoffee/views/layout.jade
create : nodecoffee/views/index.jade
install dependencies:
$ cd nodecoffee && npm install
run the app:
$ node app
很nice,連後續命令都告訴我們了。不過這個目錄結構不太MVC,以後再改,先執行第一個命令看看什麼效果。一切順利,接下來用npm ls
看看我們都install了什麼東西:
npm WARN package.json application-name@0.0.1 No README.md file found!
application-name@0.0.1 /Users/wukaixing/GitHub/nodecoffee
├─┬ express@3.3.8
│ ├── buffer-crc32@0.2.1
│ ├─┬ commander@1.2.0
│ │ └── keypress@0.1.0
│ ├─┬ connect@2.8.8
│ │ ├── bytes@0.2.0
│ │ ├── formidable@1.0.14
│ │ ├── pause@0.0.1
│ │ ├── qs@0.6.5
│ │ └── uid2@0.0.2
│ ├── cookie@0.1.0
│ ├── cookie-signature@1.0.1
│ ├── debug@0.7.2
│ ├── fresh@0.2.0
│ ├── methods@0.0.1
│ ├── mkdirp@0.3.5
│ ├── range-parser@0.0.4
│ └─┬ send@0.1.4
│ └── mime@1.2.11
├─┬ jade@0.35.0
│ ├── character-parser@1.2.0
│ ├── commander@2.0.0
│ ├─┬ constantinople@1.0.2
│ │ └─┬ uglify-js@2.4.0
│ │ ├── async@0.2.9
│ │ ├─┬ optimist@0.3.7
│ │ │ └── wordwrap@0.0.2
│ │ ├─┬ source-map@0.1.29
│ │ │ └── amdefine@0.0.8
│ │ └── uglify-to-browserify@1.0.1
│ ├── mkdirp@0.3.5
│ ├─┬ monocle@1.1.50
│ │ └─┬ readdirp@0.2.5
│ │ └─┬ minimatch@0.2.12
│ │ ├── lru-cache@2.3.1
│ │ └── sigmund@1.0.0
│ ├─┬ transformers@2.1.0
│ │ ├─┬ css@1.0.8
│ │ │ ├── css-parse@1.0.4
│ │ │ └── css-stringify@1.0.5
│ │ ├─┬ promise@2.0.0
│ │ │ └── is-promise@1.0.0
│ │ └─┬ uglify-js@2.2.5
│ │ ├─┬ optimist@0.3.7
│ │ │ └── wordwrap@0.0.2
│ │ └─┬ source-map@0.1.29
│ │ └── amdefine@0.0.8
│ └─┬ with@1.1.1
│ └─┬ uglify-js@2.4.0
│ ├── async@0.2.9
│ ├─┬ optimist@0.3.7
│ │ └── wordwrap@0.0.2
│ ├─┬ source-map@0.1.29
│ │ └── amdefine@0.0.8
│ └── uglify-to-browserify@1.0.1
└─┬ less-middleware@0.1.12
├─┬ less@1.4.2
│ ├── mime@1.2.11
│ ├─┬ request@2.21.0
│ │ ├── aws-sign@0.3.0
│ │ ├── cookie-jar@0.3.0
│ │ ├── forever-agent@0.5.0
│ │ ├─┬ form-data@0.0.8
│ │ │ ├── async@0.2.9
│ │ │ └─┬ combined-stream@0.0.4
│ │ │ └── delayed-stream@0.0.5
│ │ ├─┬ hawk@0.13.1
│ │ │ ├─┬ boom@0.4.2
│ │ │ │ └── hoek@0.9.1
│ │ │ ├── cryptiles@0.2.2
│ │ │ ├── hoek@0.8.5
│ │ │ └─┬ sntp@0.2.4
│ │ │ └── hoek@0.9.1
│ │ ├─┬ http-signature@0.9.11
│ │ │ ├── asn1@0.1.11
│ │ │ ├── assert-plus@0.1.2
│ │ │ └── ctype@0.5.2
│ │ ├── json-stringify-safe@4.0.0
│ │ ├── node-uuid@1.4.1
│ │ ├── oauth-sign@0.3.0
│ │ ├── qs@0.6.5
│ │ └── tunnel-agent@0.3.0
│ └── ycssmin@1.0.1
└── mkdirp@0.3.5
很多,也不知道都是幹嘛用的。為了保證以後換了環境重新install不會出現相容性問題,先把 package.json 改一下,明確jade和less-middleware的版本號,改成這樣:
{
"name": "node-express-coffee",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "3.3.8",
"jade": "0.35.0",
"less-middleware": "0.1.12"
}
}
執行node app,執行app.js檔案,在瀏覽器裡訪問app.js中設定的兩個route '/' 和 '/users' :
app.get('/', routes.index);
app.get('/users', user.list);
頁面正確顯示了routes目錄下index、user的響應結果。
工作環境
用node-dev,不再重啟
node-dev是用來做程式碼熱載入的node.js 開發工具,還支援coffeescript和livescript。可以通過npm做全域性安裝:
npm install -g node-dev
這樣在任何目錄下都可以執行node-dev,開發時就可以用node-dev代替node執行程式。
也可以作為開發依賴項加到package.json中:
"devDependencies": {
"node-dev": "latest"
}
為了方便,可以建立一個指令碼檔案來執行開發環境下的程式啟動,bin/dev:
#!/bin/bash
NODE_ENV=development node-dev app
如果是放在了專案的modules中,要把node-dev 改成 ./node_modules/node-dev/bin/node-dev 以指明實際路徑。以後每次啟動程式,就只需要執行bin/dev了。
把程式碼放到github上
在Github上新建一個repository放程式碼 : nodecoffee。因為本地目錄已經有了,所以要麻煩一點:
##其實就是把.git拽下來放到原來那個目錄裡,然後恢復下狀態
git clone --no-checkout nodecoffee-url nodecoffee/nodecoffee.tmp
mv nodecoffee/nodecoffee.tmp/.git nodecoffee/
rmdir nodecoffee/nodecoffee.tmp
cd nodecoffee
git reset --hard HEAD
建立.gitignore檔案,把node-modules排除掉,然後git commit
再 git push
到github上去。
把應用部署到heroku
按照heroku的文件沒有成功,git push 時失敗了,看到有人在fuck GFW,並給出瞭解決方案。要設定配置檔案,用沒被牆掉的IP地址,vi ~/.ssh/config
,內容如下:
Host heroku.com
User freemember007
Hostname 107.21.95.3
PreferredAuthentications publickey
IdentityFile ~/.ssh/id_rsa
port 22
如果遇到Permission denied (publickey)的錯誤,找到自己的public key,上傳到heroku上。
heroku keys:add ~/.ssh/id_rsa.pub
在heroku上配置域名,然後設定域名解析為CNAME,就可以訪問www.nodecoffee.com了。
解構app.js
解讀app.js
express 生成的web程式主檔案是app.js,所以我們從這個檔案入手,瞭解如何用express構建web程式,並順手把它拆了,做成適合更大應用的結構。到處都有的require
就不提了。
建立
require之後建立一個express應用程式:
var app = express();
這個可以留在app.js中。
配置
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(app.router);
app.use(require('less-middleware')({ src: __dirname + '/public' }));
app.use(express.static(path.join(__dirname, 'public')));
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
app.set
用來設定環境變數,第一個引數是環境變數的name,第二個引數是值;在其他需要訪問環境變數的地方,可以用app.get
獲取,比如上面的app.get('env')
。下面是一些內建Express環境變數:
env
執行時環境,預設為 process.env.NODE_ENV 或者 "development"trust proxy
啟用反向代理,預設未啟用狀態jsonp callback name
修改預設?callback=的jsonp回撥的名字json replacer
JSON replacer 替換時的回撥, 預設為nulljson spaces
JSON 響應的空格數量,開發環境下是2 , 生產環境是0case sensitive routing
路由的大小寫敏感, 預設是關閉狀態, "/Foo" 和"/foo" 是一樣的strict routing
路由的嚴格格式, 預設情況下 "/foo" 和 "/foo/" 是被同樣對待的view cache
模板快取,在生產環境中是預設開啟的view engine
模板引擎views
模板的目錄
我們用到了最後兩個,設定了頁面顯示的模板引擎和儲存模板的目錄。
設定app.use([path], function)是指在訪問字首為path
的路徑執行時中間函式function
,上面的程式碼中沒有指定path
,則表示在訪問預設字首/
的路徑時執行中間函式function
。比如上面程式碼中的
app.use(require('less-middleware')({ src: __dirname + '/public' }));
app.use(express.static(path.join(__dirname, 'public')));
在訪問請求靜態檔案/stylesheets/style.css
時,就會先執行less-middleware,再執行express.static
,返回public/stylesheets/style.css
給瀏覽器端。
app.use()
的出場順序非常重要,use的先後順序決定了中間函式的優先順序。 比如 express.logger()
通常是第一個,可以記錄全部請求。如果不想記錄靜態檔案的請求,可以把less-middleware和 app.use(express.static)
放到logger
前面。
在express以前的版本中有個app.configure()方法,該方法雖然仍得以保留,但推薦使用if
代替:
if ('development' == app.get('env'))
因為以後還會有很多配置,所以我們要把這部分內容提取出來放到單獨的檔案中,建立/config/express.coffee
做這些配置,而在app.js中用require代替這部分程式碼:
require('./config/express')(app);
至於express.coffee的內容,以及如何支援coffeescript,後面再講。
路由
express的路由是用方法app.VERB(path, [callback...], callback)
設定的,在上面的程式碼中體現就是:
app.get('/', routes.index);
app.get('/users', user.list);
app.VERB()
中的 VERB 是指某一個HTTP 動作, 比如 app.get()
、app.post()
。 每個path都可以對應多個callbacks,這些callbacks跟中間函式一樣,按順序逐一執行,但也有例外,如果某個callback執行了next('route')
,它後面的callback就被忽略。
前面的路徑字串path是當做正規表示式處理的,在遇到符合規則的http請求時執行callbacks。 path中不考慮請求引數,比如 "GET /" 會匹配下面的這個路由, 而"GET /?name=tobi"也會匹配。
app.get('/', routes.index);
因為程式要處理的路徑肯定不止這兩條,所以這些也要從app.js裡拿出來,放到另外的檔案裡。在app.js中用
require('./config/routes')(app);
代替。/config/routes.coffee檔案也要在下一節給出了。
啟動
檔案最後的程式碼是啟動伺服器,並輸出一段日誌:
http.createServer(app).listen(app.get('port'), function(){
console.log('NodeCoffee server listening on port ' + app.get('port'));
});
這個也要保留在app.js中
拆分app.js
因為express生成的app.js不適用比較大的程式,所以我們要把它拆開,最終的檔案如下所示:
var express = require('express');
var http = require('http');
var path = require('path');
var app = express();
require('./config/express')(app);
require('./config/routes')(app);
http.createServer(app).listen(app.get('port'), function(){
console.log('NodeCoffee server listening on port ' + app.get('port'));
});
從上面的程式碼可以看出來,我們把配置資訊都放到了config目錄下,又建立了兩個檔案。此外,原來routes下的檔案也被挪走了,因為它們其實不是routes,是controller來的。
所以我們又遵循MVC模式新建了三個目錄app/controllers、app/models、app/views,原來routes目錄下的兩個檔案挪到controllers,views目錄也挪到了app下。
因為我們以後要用coffeescript寫程式碼,所以要先把coffeescript引入專案,在package.json中的dependencies里加一條:
"coffee-script": "1.6.3"
此外還要在app.js裡引入 require('coffee-script');
,然後就可以開始用coffeescript改程式碼了。上兩段程式碼:
config/express.coffee:
express = require 'express'
path = require 'path'
module.exports = (app,config) ->
#all environments
app.set "port", process.env.PORT or 3000
app.set('showStackError', true)
app.set('views', config.root + '/app/views')
app.set "view engine", "jade"
app.use express.favicon()
app.use express.logger("dev")
app.use express.bodyParser()
app.use express.methodOverride()
app.use express.cookieParser("p8zztgch48rehu79jskhm6aj3")
app.use express.session()
app.use app.router
app.use require("less-middleware")(src: __dirname + "/public")
app.use express.static(path.join(__dirname, "public"))
# development only
app.use express.errorHandler() if "development" is app.get("env")
config/routes.coffee:
module.exports = (app) ->
home = require '../app/controllers/home'
app.get '/', home.index
user = require '../app/controllers/user'
app.get '/users', user.list
原來routes目錄下的index.js改成了/app/controllers/home.coffee,user.js改成了user.coffee。
express的基本配置項
上一節講到app.js中有一段程式碼用app.set
和app.use
對express進行配置,但這些配置都是什麼意思,以及都能做哪些配置並沒有展開。這一節就專門來講express的配置。上節已經介紹了幾個設定,接下來先介紹剩下的幾個:
app.use(express.favicon());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('your secret here'));
app.use(express.session());
app.use(app.router);
express.favicon(iconPath)
:用來設定網站的圖示,引數為圖示的路徑。如果不指明,則用預設的express圖示。可以修改為:
app.use(express.favicon(path.join(__dirname, '../public/img/favicon.ico')))
express.bodyParser()
: 對請求內容進行解析,支援json、 application/x-www-form-urlencoded、multipart/form-data 格式資料的解析。也就是說ajax和form傳送請求時,都會經過它的處理,方便在req中獲取相應的請求值。在express中處理檔案上傳也是用它,可以給出引數指明上傳檔案存放的路徑,比如:
app.use(express.bodyParser({uploadDir:'./uploads'}))
express.methodOverride()
:為了支援put、delete等HTTP方法,不過要客戶端配合,包含相應的_method
引數,比如:
<form action='/users/1'> ...
<input type="hidden" name="_method" value="put" />
</form>
可以對應到:
app.put('/users/:id', users.put)
app.use(express.cookieParser('your secret here'));
和app.use(express.session());
:是為了支援session,在這樣的設定中,session會被加密儲存在客戶端的cookie,但這樣程式重啟後session就不起作用了,不過express.session支援session的持久化儲存,因為express用的最多的資料庫就是mongo,所以下面給出用mongo儲存session的配置。首先要在package.json里加上依賴項connect-mongo
:
"connect-mongo": "0.3.3"
然後在config/express.coffee中引入connect-mongo,並修改express.session的設定:
mongoStore = require('connect-mongo')(express)
app.use express.session
secret: '1234567890'
store: new mongoStore
url: config.db,
collection : 'sessions'
app.router
是connect router的加強版,用來處理app.get
,app.post
等請求處理設定,在瀏覽器訪問這些設定中對應的url時,express.router
會呼叫相應的function。如果不顯式呼叫app.use(app.router)
,express會在第一次碰到app.get(...)
之類的設定時隱含呼叫,所以這個可以不用出現在配置項裡,但.use
的順序很關鍵,所以顯式呼叫比較好。比如在use
中出現app.use(express.static(path.join(__dirname, 'public')));
時,如果router沒有出現,或被放在了它後面,那伺服器每次遇到請求就會到硬碟上找有沒有對應的靜態檔案,會造成效能下降。
這些是express最基本的配置項,其他常用的配置項,比如壓縮、資料校驗、認證和授權等都可以放在這裡,下節繼續介紹。
express配置項more
前面對express配置的介紹都是基於它所生成的app.js檔案,現在去翻翻express的API文件,看看還有什麼。
express把API分成了四部分:Application、request、response、middleware。這四部分是express的關注點,其中最重要的是request
和response
兩部分,和大多數web框架一樣。
在application部分中,跟配置相關的set
,get
和use
前面介紹過了,還有一個很重要的:
app.locals:這是一個函式物件,可以給它增加新的屬性。程式內所有頁面模板都能訪問這個物件,所以可以用它儲存全域性配置變數供頁面模板使用。
預設情況下express只有一個應用級變數,即可以由set()
設定的settings
,比如:
app.set('title', 'NodeCoffee');
#在view裡使用 settings.title
app.locals
可以有幾種不同的用法。可以直接增加屬性賦值:
app.locals.title = 'NodeCoffee'
也可以呼叫方法直接傳入一個物件:
app.locals(
title: 'NodeCoffee'
phone: '1150-858-9990'
email: 'me@nodecoffee.com'
)
因為在javascript的函數語言程式設計特性,所以也可以把函式傳到模板中使用,比如:
app.locals._ = require "underscore"
在request部分,沒有配置項,真沒有。
在response部分,有一個跟app.locals
對應的res.locals
。res.locals
用於儲存請求級變數,它的用法跟app.locals
一樣,比如剛才的title
等變數也可以放在res.locals
中,但不能直接在配置中賦值,要用app.use
以middleware的方式設定。比如middleware view-helpers就是用res.locals
儲存請求級變數,其中部分程式碼如下:
res.locals.appName = name || 'App'
res.locals.title = name || 'App'
res.locals.req = req
res.locals.isActive = function (link) {
return req.url.indexOf(link) !== -1 ? 'active' : ''
}
res.locals.formatDate = formatDate
res.locals.stripScript = stripScript
res.locals.createPagination = createPagination(req)
其中的formatDate
、stripScript
和createPagination
都是它定義的函式,要在view中使用。
middleware是express重要的請求處理機制,在express的配置中可以通過.use()
讓多個middleware構成請求的處理鏈,除了express提供的middleware,還有很多第三方middleware,比如上文提到的view-helpers,還有用於使用者驗證的passport等。我們先來介紹兩個express的middleware:
express.compress()
:通過gzip / deflate壓縮響應資料. 這個中介軟體應該放置在所有的中介軟體最前面以保證所有的返回都是被壓縮的。不過也可以只對文字內容進行壓縮,比如:
app.use express.compress
filter: (req, res) ->
return /json|text|javascript|css/.test(res.getHeader('Content-Type'))
level: 9
express.csrf()
:這是為防護CSRF攻擊的middleware,伺服器會為每個使用者產生一個唯一的"_csrf"標識,儲存在使用者的session中,對於那些需要伺服器更改的請求,伺服器會對req.session._csrf
屬性進行校驗,如果客戶端發過來的這個屬性與儲存在session中的值一致,則通過,否則返回304響應。
它需要session支援,因此應該放在.use(express.session())
之後。
以上是express自帶的middleware,此外我們還要再介紹兩個常用的第三方middleware。第一個是用於輸入資料校驗的express-validator,另一個是用於使用者驗證的passport。
express-validator是第三方middleware,所以要使用它需要先在package.json中加入依賴項:
"express-validator":"0.8.0"
然後在config/express.coffee中引入,配置如下:
expressValidator = require('express-validator')
app.use(expressValidator(
errorFormatter: (param, msg, value)->
namespace = param.split('.')
root = namespace.shift()
formParam = root
while(namespace.length)
formParam += '[' + namespace.shift() + ']'
param : formParam
msg : msg
value : value
))
express-validator的配置要放在express.bodyParser
之後,至於這個validator如何使用,將在controller中介紹。
passport的配置稍微複雜一點,這裡不展開講它的全部配置,只介紹作為middleware在express中的設定。只需要兩行程式碼:
app.use passport.initialize()
app.use passport.session()
第一行是passport的初始化,第二行是為了配合在session中儲存驗證侯的使用者資訊。下一節會以使用者註冊及登入為例介紹如何編寫express web程式,還會詳細講解passport的使用。
相關文章
- node express web開發框架ExpressWeb框架
- Express 4.x Node.js的Web框架ExpressNode.jsWeb框架
- express框架Express框架
- Ubuntu下搭建NodeJS+Express WEB開發框架UbuntuNodeJSExpressWeb框架
- 採用 SwiftNIO 實現一個類似 Express 的 Web 框架SwiftExpressWeb框架
- express快速搭建web serverExpressWebServer
- Node.js Express 框架Node.jsExpress框架
- 初次接觸express框架Express框架
- node框架express的研究框架Express
- Express框架(二)—— 中介軟體Express框架
- Node.js框架之expressNode.js框架Express
- node中express框架使用詳解Express框架
- 用“MEAN”技術棧開發web應用(二)express搭建服務端框架WebExpress服務端框架
- express框架+mongodb簡易學生管理Express框架MongoDB
- nodejs express 框架解密4-路由NodeJSExpress框架解密路由
- nodejs express 框架解密5-檢視NodeJSExpress框架解密
- 用原生http 實現簡單 Express 框架HTTPExpress框架
- CentOS安裝執行NodeJS框架ExpressCentOSNodeJS框架Express
- 前端web框架前端Web框架
- web ui 框架WebUI框架
- Web services框架Web框架
- 使用nodejs和express搭建http web服務NodeJSExpressHTTPWeb
- nodejs中express搭建本地web伺服器NodeJSExpressWeb伺服器
- node-express框架本地模擬介面資料Express框架
- 第四代Express框架koa簡介Express框架
- CentOS安裝NodeJS及Express開發框架CentOSNodeJSExpress框架
- [譯]Node.js框架對比:Express/Koa/HapiNode.js框架ExpressAPI
- IBM 向 Node.js 捐贈 Express 框架,為 Express 醜聞畫上了句號IBMNode.jsExpress框架
- golang web框架,golang版本laravel 框架GolangWeb框架Laravel
- nodejs express 框架解密1-總體結構NodeJSExpress框架解密
- nodejs express 框架解密3-中介軟體模組NodeJSExpress框架解密
- Rust Web框架列表RustWeb框架
- Java Web UI框架JavaWebUI框架
- Python Web框架PythonWeb框架
- JdonFramework web框架整合FrameworkWeb框架
- Web框架自身安全Web框架
- 自己編寫Java Web框架:Takes框架的Web App架構JavaWeb框架APP架構
- wsgiref模組、web框架、django框架簡介Web框架Django