淺談Node.js輕量級(jí)Web框架Express4.x使用指南
Express是一個(gè)輕量級(jí)的Web框架,簡(jiǎn)單、靈活
也是目前最流行的基于Nodejs的Web框架
通過(guò)它我們可以快速搭建功能完整的網(wǎng)站 (express 英文意思:特快列車(chē))
Express現(xiàn)在是4.x版本,更新很快,并且不兼容舊版本,導(dǎo)致現(xiàn)在市面上很多優(yōu)秀的Node書(shū)籍過(guò)時(shí)
這篇文章是一篇入門(mén)級(jí)的Express使用,需要一定Node.js的基礎(chǔ)
Web應(yīng)用創(chuàng)建
首先要做的是下載express并引用
npm install express --save
全局安裝就+個(gè)-g
引用express
var express = require('express'); var app = express();
通過(guò)app我們就可以使用各種express的API
在3.x版本的時(shí)候是這樣寫(xiě)的
var app =express.createServer();
現(xiàn)在這個(gè)函數(shù)已經(jīng)被拋棄了
下面正式創(chuàng)建應(yīng)用
//app.js var express = require('express'); var app = express(); app.get('/', function(req, res){ res.send('Express'); }); app.listen(3000);
啟動(dòng)之后就能給夠在頁(yè)面看到效果
$ node app.js
app.get()
上面的app.listen()就不多說(shuō)了
用于監(jiān)聽(tīng)端口
app.get(path, function(req, res){ })
用于用于處理客戶(hù)端向服務(wù)器發(fā)送的GET請(qǐng)求
path表示請(qǐng)求的路徑
回調(diào)函數(shù)的req和res是request和response的意思
request表示客戶(hù)端發(fā)送的HTTP請(qǐng)求信息
response表示服務(wù)器發(fā)送的HTTP響應(yīng)信息
使用res.send()可以向客戶(hù)端發(fā)送信息
//app.js var express = require('express'); var app = express(); app.get('/', function(req, res){ res.send('<h1>Express</h1>'); }); app.get('/demo', function(req, res){ res.send('<h1>Demo</h1>'); }) app.get('/*', function(req, res){ res.send('<h1>404<h1>'); }) app.listen(3000);
app.post()
app.post(path, function(req, res){ })
用于用于處理客戶(hù)端向服務(wù)器發(fā)送的POST請(qǐng)求
和GET請(qǐng)求不同,POST請(qǐng)求不會(huì)將信息放在url中
而是寫(xiě)入請(qǐng)求頭中
它的解析有所不同,下面再說(shuō)
app.all()
在此之前還要提一個(gè)概念——中間件
Middleware中間件在不同環(huán)境下有不同含義
而在我們express中,簡(jiǎn)單說(shuō)它就是一個(gè)特殊的函數(shù)
用來(lái)處理HTTP請(qǐng)求的函數(shù)
并且它有一個(gè)特點(diǎn)——處理完一個(gè)中間件可以傳遞給下一個(gè)中間件來(lái)處理
funciton(req, res, next){ ... next(); }
(如果不使用執(zhí)行next函數(shù),那么之后監(jiān)聽(tīng)的函數(shù)也不會(huì)執(zhí)行)
可以向next中傳遞字符串參數(shù),代表拋出的錯(cuò)誤信息
這樣當(dāng)數(shù)據(jù)往下傳遞的時(shí)候,中間件不再進(jìn)行處理
直到找到一個(gè)錯(cuò)誤處理函數(shù)為止
在app.all(path, function(req, res, next){ })
的使用中
就需要我們定義這樣的中間件
這個(gè)方法可以過(guò)濾所有路徑上的請(qǐng)求
換句話說(shuō),在其他所有的中間件處理之前
必須先通過(guò)app.all()的中間件進(jìn)行處理
var express = require('express'); var app = express(); app.all('*', function(req, res, next){ res.writeHead(200, ':)'); next(); }); app.get('/', function(req, res){ res.end('<h1>Express</h1>'); }); app.get('/demo', function(req, res){ res.end('<h1>Demo</h1>'); }) app.get('/*', function(req, res){ res.end('<h1>404<h1>'); }) app.listen(3000);
這樣不論客戶(hù)端向我們發(fā)出了什么樣的路徑請(qǐng)求
服務(wù)器響應(yīng)信息前都會(huì)先打上響應(yīng)頭
app.use()
app.use([path, ]function(req, res, next){ })
這個(gè)方法一般情況是用來(lái)調(diào)用中間件的
與前面的函數(shù)不同,它的第一個(gè)path參數(shù)可以省略,默認(rèn)'/'
app.use(express.static(path.join(__dirname, '/public')));
上面的這個(gè)用法就是指定靜態(tài)文件的訪問(wèn)路徑
通過(guò)next參數(shù)我們可以連續(xù)調(diào)用中間件函數(shù)
app.use(function(req, res, next){ console.log(1); next(); }); app.use(function(req, res, next){ console.log(2); next(); }); app.use(function(req, res, next){ console.log(3); }); app.use(function(req, res, next){ console.log(4); });
當(dāng)發(fā)出網(wǎng)絡(luò)請(qǐng)求的時(shí)候
控制臺(tái)就會(huì)輸出 1 2 3
因?yàn)榈谌齻€(gè)中間件沒(méi)有調(diào)用next方法
所以處理到此為止
不會(huì)輸出4
app.use()除了調(diào)用中間件
還可以根據(jù)請(qǐng)求路徑的不同,返回不同信息
但我們一般不會(huì)這么用
//app.js var express = require('express'); var app = express(); app.use(function(req, res, next){ if(req.url == '/'){ res.end('<h1>Express</h1>'); }else{ next(); } }); app.use(function(req, res, next){ if(req.url == '/demo'){ res.end('<h1>Demo</h1>'); }else{ next(); } }); app.use(function(req, res, next){ res.end('<h1>404<h1>'); }); app.listen(3000);
請(qǐng)求與響應(yīng)
上面express中每一個(gè)回調(diào)函數(shù)都不可缺少req和res參數(shù)
重要性可見(jiàn)一斑
常見(jiàn)的req與res中的屬性/方法如下(原生node.js的req、res屬性/方法也可以使用)
Request對(duì)象:
API | 含義 |
---|---|
req.app | 當(dāng)callback為外部文件時(shí),用于訪問(wèn)express的實(shí)例 |
req.baseUrl | 獲取路由當(dāng)前安裝的URL路徑 |
req.body/cookies | 獲得「請(qǐng)求主體」/ Cookies |
req.fresh/stale | 判斷請(qǐng)求是否還「新鮮」 |
req.hostname/ip | 獲取主機(jī)名和IP地址 |
req.originalUrl | 獲取原始請(qǐng)求URL |
req.params | 獲取路由的parameters |
req.path | 獲取請(qǐng)求路徑 |
req.protocol | 獲取協(xié)議類(lèi)型 |
req.query | 獲取URL的查詢(xún)參數(shù)串 |
req.route | 獲取當(dāng)前匹配的路由 |
req.subdomains | 獲取子域名 |
req.acceptsCharsets | 返回指定字符集的第一個(gè)可接受字符編碼 |
req.acceptsEncodings | 返回指定字符集的第一個(gè)可接受字符編碼 |
req.acceptsLanguages | 返回指定字符集的第一個(gè)可接受字符編碼 |
req.accepts() | 檢查可接受的請(qǐng)求的文檔類(lèi)型 |
req.get() | 獲取指定的HTTP請(qǐng)求頭 |
req.is() | 判斷請(qǐng)求頭Content-Type的MIME類(lèi)型 |
Response對(duì)象:
API | 含義 |
---|---|
res.app | 同req.app |
res.append() | 追加指定HTTP頭 |
res.set() | 在res.append()后將重置之前設(shè)置的頭 |
res.cookie() | 設(shè)置Cookie |
res.clearCookie() | 清除Cookie |
res.download() | 傳送指定路徑的文件 |
res.get() | 返回指定的HTTP頭 |
res.json() | 傳送JSON響應(yīng) |
res.jsonp() | 傳送JSONP響應(yīng) |
res.location() | 只設(shè)置響應(yīng)的Location HTTP頭,不設(shè)置狀態(tài)碼或者close response |
res.redirect() | 設(shè)置響應(yīng)的Location HTTP頭,并且設(shè)置狀態(tài)碼302 |
res.send() | 傳送HTTP響應(yīng) |
res.sendFile() | 傳送指定路徑的文件 -會(huì)自動(dòng)根據(jù)文件extension設(shè)定Content-Type |
res.set() | 設(shè)置HTTP頭,傳入object可以一次設(shè)置多個(gè)頭 |
res.status() | 設(shè)置HTTP狀態(tài)碼 |
res.type() | 設(shè)置Content-Type的MIME類(lèi)型 |
挑一些重點(diǎn)
req.query
req.query可以獲取請(qǐng)求路徑參數(shù)的對(duì)象
向服務(wù)器發(fā)送請(qǐng)求 http://localhost:3000/?user=tester&pass[a]=123&pass[b]=456
//app.js var express = require('express'); var app = express(); app.get('/', function(req, res, next){ console.log(req.query); console.log(req.query.user); //tester console.log(req.query.pass.a); //123 console.log(req.query.pass.b); //456 res.end(); }); app.listen(3000);
req.params
req.params可以解析復(fù)雜路由規(guī)則上的屬性
(req.param綜合了req.query和req.param的功能,但是被移除了不要使用)
向服務(wù)器發(fā)送請(qǐng)求 http://localhost:3000/123456
//app.js var express = require('express'); var app = express(); app.get('/:id', function(req, res, next){ console.log(req.params.id); //123456 res.end(); }); app.listen(3000);
這樣不論我在根路徑后輸入的是什么
都會(huì)被解析為req.params.id
res.send()
res.send用于向客戶(hù)端響應(yīng)信息 并且它的強(qiáng)大之處在于可以智能的處理我們傳遞的不同類(lèi)型參數(shù)
app.get('/', function(req, res, next){ res.send('express'); });
當(dāng)參數(shù)為字符串,會(huì)將響應(yīng)頭Content-Type默認(rèn)設(shè)置為text/html
也就是解析為html呈現(xiàn)在我們的頁(yè)面上
app.get('/', function(req, res){ res.send(200); });
當(dāng)參數(shù)為數(shù)字,會(huì)自動(dòng)幫我們?cè)O(shè)置響應(yīng)體(狀態(tài)碼…)
app.get('/', function(req, res){ res.send([1, 2, 3]); });
當(dāng)參數(shù)為數(shù)組或?qū)ο?,它?huì)響應(yīng)一個(gè)JSON
res.redirect()
使用這個(gè)方法可以讓我們對(duì)網(wǎng)頁(yè)重定向
比如使用絕對(duì)url跳轉(zhuǎn)到不同的域名
app.get('/', function(req, res){ res.redirect('http://www.baidu.com'); });
res.redirect()默認(rèn)響應(yīng)狀態(tài)碼是302
可以更改這個(gè)狀態(tài)碼作為res.redirect()的第一個(gè)參數(shù)
//app.js var express = require('express'); var app = express(); app.get('/', function(req, res){ res.redirect(302, 'demo'); }); app.get('/demo', function(req, res){ res.end(); }); app.listen(3000);
當(dāng)在url地址欄中輸入http://localhost:3000
頁(yè)面就會(huì)重定向到http://localhost:3000/demo
靜態(tài)資源
靜態(tài)資源就是指我們?cè)陂_(kāi)發(fā)中用到的css、js、img等等
它們需要存放到一個(gè)靜態(tài)資源目錄
當(dāng)瀏覽器發(fā)出了一個(gè)非HTML文件請(qǐng)求
服務(wù)器就會(huì)從這個(gè)靜態(tài)資源目錄下去查找文件
我們一般在根目錄下創(chuàng)建一個(gè)public文件來(lái)存儲(chǔ)
并在public中創(chuàng)建stylesheets、javascripts、images等文件夾
用來(lái)存儲(chǔ)特定類(lèi)型的資源
指定靜態(tài)資源目錄的方法上面已經(jīng)提到了
var path = require('path'); app.use(express.static(path.join(__dirname, 'public')));
比如說(shuō)我們的html中有這樣的代碼
<link href="/javascripts/jquery.js" rel="external nofollow" rel="stylesheet" media="screen">
那么客戶(hù)端運(yùn)行發(fā)出請(qǐng)求
服務(wù)器就會(huì)在public的javascripts文件夾下找到j(luò)Query.js靜態(tài)資源
模板引擎
express框架默認(rèn)是ejs和jade渲染模板
這里以jade為例
使用時(shí)肯定要下載
npm install jade --save
再通過(guò)app.set()指定查找模板文件的目錄(類(lèi)似于靜態(tài)資源)
并指定模板文件后綴為jade
app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade');
(如果不使用模板而使用原生html,app.set('view engine', 'html');)
如果我們想要訪問(wèn)模板該怎么做呢?
很簡(jiǎn)單,只需要一個(gè)方法res.render()
現(xiàn)在我寫(xiě)了一個(gè)簡(jiǎn)單的jade模板(關(guān)于jade語(yǔ)法超出本文討論范圍)
//views/index.jade doctype html html head title= title link(rel='stylesheet', href='/stylesheets/style.css') body h1= title p= content
通過(guò)res.render渲染
//app.js var express = require('express'); var path = require('path'); var app = express(); app.use(express.static(path.join(__dirname, 'public'))); app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'jade'); app.get('/', function(req, res){ res.render('index', { title: 'Express', content: 'this is an example' }); }); app.listen(3000);
res.render()
res.render(view[, datas][, callback])
用于對(duì)網(wǎng)頁(yè)模板進(jìn)行渲染
第一個(gè)參數(shù)是要渲染的模板名稱(chēng)
第二個(gè)參數(shù)是傳遞給模板的變量,以對(duì)象形式存儲(chǔ),沒(méi)有可省略
第三個(gè)參數(shù)是渲染后回調(diào)函數(shù),可以省略
路由
路由的意思就是根據(jù)不同的路徑,來(lái)指定不同的處理方法
我們一般把不同的路由封裝進(jìn)不同的模塊
首先在根目錄下創(chuàng)建一個(gè)文件夾routes存儲(chǔ)路由
現(xiàn)在我在routes文件夾下創(chuàng)建倆個(gè)路由文件index.js和users.js
修改app.js
//app.js var express = require('express'); var path = require('path'); var app = express(); var index = require('./routes/index'); var users = require('./routes/users'); app.use('/', index); app.use('/users', users); app.listen(3000);
這樣表示http://localhost:3000/的路由交給index處理
http://localhost:3000/users的路由交給users處理
下面簡(jiǎn)單的實(shí)現(xiàn)一下路由
//routes/index.js var express = require('express'); var router = express.Router(); router.get('/', function(req, res){ res.end('index'); }); router.get('/123', function(){ res.end(123); }); module.exports = router;
//routes/users.js var express = require('express'); var router = express.Router(); router.get('/', function(req, res) { res.end('users'); }); module.exports = router;
通過(guò)express.Router()創(chuàng)建的router就像一個(gè)mini版的app一樣
app能做的,router都能做
只是我們把邏輯都封裝到了各個(gè)路由模塊中
上面代碼的結(jié)果:
body-parser中間件
作為一個(gè)入門(mén)級(jí)文章
最后就來(lái)淺顯的談一個(gè)中間件body-parser吧
其實(shí)express在3.x版本中內(nèi)置了很多中間件
但是4.x版本就將出static以外的所有中間件全部抽離出來(lái)了
所以就需要我們單獨(dú)安裝
對(duì)照表如下:
Express 3.0 | Express 4.0 |
---|---|
bodyParser | body-parser |
compress | compression |
cookieSession | cookie-session |
logger | morgan |
cookieParser | cookie-parser |
session | express-session |
favicon | static-favicon |
response-time | response-time |
error-handler | errorhandler |
method-override | method-override |
timeout | connect-timeout |
vhost | vhost |
csrf | csurf |
剛才就提到了POST請(qǐng)求有所不同
不同的地方就在于我們需要body-parser這個(gè)中間件來(lái)處理數(shù)據(jù)
通過(guò)req.body來(lái)獲得數(shù)據(jù)
首先使用前不要忘記下載
npm install body-parser --save
//app.js var express = require('express'); var bodyParser = require('body-parser'); var path = require('path'); var app = express(); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); app.get('/', function(req, res){ res.send('<form method="POST" action="./form">\ <input type="text" name="user">\ <input type="submit">\ </form>'); }); app.post('/form', function(req, res){ console.log(req.body); var user = req.body.user; res.send('賬號(hào): ' + user); }); app.listen(3000);
下面這四個(gè)方法分別用于對(duì)body內(nèi)容采取不同的處理方法
- bodyParser.json(options) 處理JSON數(shù)據(jù)
- bodyParser.raw(options) 處理buffer數(shù)據(jù)
- bodyParser.text(options) 處理文本數(shù)據(jù)
- bodyParser.urlencoded(options) 處理UTF-8編碼數(shù)據(jù)
這樣我首先通過(guò)get請(qǐng)求獲取主頁(yè)面
提交表單向服務(wù)器發(fā)送post請(qǐng)求
服務(wù)器響應(yīng)結(jié)果
express-generator
通過(guò)express-generator應(yīng)用生成器
可以為我們快速生成項(xiàng)目雛形
在你要生成項(xiàng)目的目錄中下載express-generator
npm install express-generator
然后輸入
express <項(xiàng)目文件名>
這樣express就會(huì)把必要的文件夾以及代碼快速生成了
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
nodejs報(bào)digital?envelope?routines::unsupported錯(cuò)誤的最新解決方法
這篇文章主要介紹了nodejs報(bào)digital?envelope?routines::unsupported錯(cuò)誤的最新解決方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-02-02Node.js使用對(duì)話框ngDialog的示例代碼
本篇文章主要介紹了Node.js使用對(duì)話框ngDialog的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-05-05推薦一個(gè)基于Node.js的表單驗(yàn)證庫(kù)
這篇文章主要介紹了推薦一個(gè)基于Node.js的表單驗(yàn)證庫(kù),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-02-02淺析Node.js中使用依賴(lài)注入的相關(guān)問(wèn)題及解決方法
這篇文章主要介紹了淺析Node.js中使用依賴(lài)注入的相關(guān)問(wèn)題及解決方法,Node.js是一個(gè)將JavaScript應(yīng)用運(yùn)行于服務(wù)器端的框架,需要的朋友可以參考下2015-06-06