Express是一個輕量級的Web框架,簡單、靈活
也是目前最流行的基于Nodejs的Web框架
通過它我們可以快速搭建功能完整的網(wǎng)站 (express 英文意思:特快列車)
Express現(xiàn)在是4.x版本,更新很快,并且不兼容舊版本,導(dǎo)致現(xiàn)在市面上很多優(yōu)秀的Node書籍過時
這篇文章是一篇入門級的Express使用,需要一定Node.js的基礎(chǔ)
Web應(yīng)用創(chuàng)建
首先要做的是下載express并引用
npm install express --save
全局安裝就+個-g
引用express
var express = require('express');var app = express();
通過app我們就可以使用各種express的API
在3.x版本的時候是這樣寫的
var app =express.createServer();
現(xiàn)在這個函數(shù)已經(jīng)被拋棄了
下面正式創(chuàng)建應(yīng)用
//app.jsvar express = require('express');var app = express();app.get('/', function(req, res){ res.send('Express');});app.listen(3000);
啟動之后就能給夠在頁面看到效果
$ node app.js
app.get()
上面的app.listen()就不多說了
用于監(jiān)聽端口
app.get(path, function(req, res){ })
用于用于處理客戶端向服務(wù)器發(fā)送的GET請求
path表示請求的路徑
回調(diào)函數(shù)的req和res是request和response的意思
request表示客戶端發(fā)送的HTTP請求信息
response表示服務(wù)器發(fā)送的HTTP響應(yīng)信息
使用res.send()可以向客戶端發(fā)送信息
//app.jsvar 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){ })
用于用于處理客戶端向服務(wù)器發(fā)送的POST請求
和GET請求不同,POST請求不會將信息放在url中
而是寫入請求頭中
它的解析有所不同,下面再說
app.all()
在此之前還要提一個概念――中間件
Middleware中間件在不同環(huán)境下有不同含義
而在我們express中,簡單說它就是一個特殊的函數(shù)
用來處理HTTP請求的函數(shù)
并且它有一個特點――處理完一個中間件可以傳遞給下一個中間件來處理
funciton(req, res, next){ ... next();}
(如果不使用執(zhí)行next函數(shù),那么之后監(jiān)聽的函數(shù)也不會執(zhí)行)
可以向next中傳遞字符串參數(shù),代表拋出的錯誤信息
這樣當(dāng)數(shù)據(jù)往下傳遞的時候,中間件不再進(jìn)行處理
直到找到一個錯誤處理函數(shù)為止
在app.all(path, function(req, res, next){ })
的使用中
就需要我們定義這樣的中間件
這個方法可以過濾所有路徑上的請求
換句話說,在其他所有的中間件處理之前
必須先通過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);
這樣不論客戶端向我們發(fā)出了什么樣的路徑請求
服務(wù)器響應(yīng)信息前都會先打上響應(yīng)頭
app.use()
app.use([path, ]function(req, res, next){ })
這個方法一般情況是用來調(diào)用中間件的
與前面的函數(shù)不同,它的第一個path參數(shù)可以省略,默認(rèn)'/'
app.use(express.static(path.join(__dirname, '/public')));
上面的這個用法就是指定靜態(tài)文件的訪問路徑
通過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ò)請求的時候
控制臺就會輸出 1 2 3
因為第三個中間件沒有調(diào)用next方法
所以處理到此為止
不會輸出4
app.use()除了調(diào)用中間件
還可以根據(jù)請求路徑的不同,返回不同信息
但我們一般不會這么用
//app.jsvar 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);
請求與響應(yīng)
上面express中每一個回調(diào)函數(shù)都不可缺少req和res參數(shù)
重要性可見一斑
常見的req與res中的屬性/方法如下(原生node.js的req、res屬性/方法也可以使用)
Request對象:
API | 含義 |
---|---|
req.app | 當(dāng)callback為外部文件時,用于訪問express的實例 |
req.baseUrl | 獲取路由當(dāng)前安裝的URL路徑 |
req.body/cookies | 獲得「請求主體」/ Cookies |
req.fresh/stale | 判斷請求是否還「新鮮」 |
req.hostname/ip | 獲取主機名和IP地址 |
req.originalUrl | 獲取原始請求URL |
req.params | 獲取路由的parameters |
req.path | 獲取請求路徑 |
req.protocol | 獲取協(xié)議類型 |
req.query | 獲取URL的查詢參數(shù)串 |
req.route | 獲取當(dāng)前匹配的路由 |
req.subdomains | 獲取子域名 |
req.acceptsCharsets | 返回指定字符集的第一個可接受字符編碼 |
req.acceptsEncodings | 返回指定字符集的第一個可接受字符編碼 |
req.acceptsLanguages | 返回指定字符集的第一個可接受字符編碼 |
req.accepts() | 檢查可接受的請求的文檔類型 |
req.get() | 獲取指定的HTTP請求頭 |
req.is() | 判斷請求頭Content-Type的MIME類型 |
Response對象:
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() | 傳送指定路徑的文件 -會自動根據(jù)文件extension設(shè)定Content-Type |
res.set() | 設(shè)置HTTP頭,傳入object可以一次設(shè)置多個頭 |
res.status() | 設(shè)置HTTP狀態(tài)碼 |
res.type() | 設(shè)置Content-Type的MIME類型 |
挑一些重點
req.query
req.query可以獲取請求路徑參數(shù)的對象
向服務(wù)器發(fā)送請求 http://localhost:3000/?user=tester&pass[a]=123&pass[b]=456
//app.jsvar 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ā)送請求 http://localhost:3000/123456
//app.jsvar express = require('express');var app = express();app.get('/:id', function(req, res, next){ console.log(req.params.id); //123456 res.end();});app.listen(3000);
這樣不論我在根路徑后輸入的是什么
都會被解析為req.params.id
res.send()
res.send用于向客戶端響應(yīng)信息 并且它的強大之處在于可以智能的處理我們傳遞的不同類型參數(shù)
app.get('/', function(req, res, next){ res.send('express');});
當(dāng)參數(shù)為字符串,會將響應(yīng)頭Content-Type默認(rèn)設(shè)置為text/html
也就是解析為html呈現(xiàn)在我們的頁面上
app.get('/', function(req, res){ res.send(200);});
當(dāng)參數(shù)為數(shù)字,會自動幫我們設(shè)置響應(yīng)體(狀態(tài)碼…)
app.get('/', function(req, res){ res.send([1, 2, 3]);});
當(dāng)參數(shù)為數(shù)組或?qū)ο螅鼤憫?yīng)一個JSON
res.redirect()
使用這個方法可以讓我們對網(wǎng)頁重定向
比如使用絕對url跳轉(zhuǎn)到不同的域名
app.get('/', function(req, res){ res.redirect('http://www.baidu.com');});
res.redirect()默認(rèn)響應(yīng)狀態(tài)碼是302
可以更改這個狀態(tài)碼作為res.redirect()的第一個參數(shù)
//app.jsvar 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
頁面就會重定向到http://localhost:3000/demo
靜態(tài)資源
靜態(tài)資源就是指我們在開發(fā)中用到的css、js、img等等
它們需要存放到一個靜態(tài)資源目錄
當(dāng)瀏覽器發(fā)出了一個非HTML文件請求
服務(wù)器就會從這個靜態(tài)資源目錄下去查找文件
我們一般在根目錄下創(chuàng)建一個public文件來存儲
并在public中創(chuàng)建stylesheets、javascripts、images等文件夾
用來存儲特定類型的資源
指定靜態(tài)資源目錄的方法上面已經(jīng)提到了
var path = require('path');app.use(express.static(path.join(__dirname, 'public')));
比如說我們的html中有這樣的代碼
<link href="/javascripts/jquery.js" rel="external nofollow" rel="stylesheet" media="screen">
那么客戶端運行發(fā)出請求
服務(wù)器就會在public的javascripts文件夾下找到j(luò)Query.js靜態(tài)資源
模板引擎
express框架默認(rèn)是ejs和jade渲染模板
這里以jade為例
使用時肯定要下載
npm install jade --save
再通過app.set()指定查找模板文件的目錄(類似于靜態(tài)資源)
并指定模板文件后綴為jade
app.set('views', path.join(__dirname, 'views'));app.set('view engine', 'jade');
(如果不使用模板而使用原生html,app.set('view engine', 'html');)
如果我們想要訪問模板該怎么做呢?
很簡單,只需要一個方法res.render()
現(xiàn)在我寫了一個簡單的jade模板(關(guān)于jade語法超出本文討論范圍)
//views/index.jadedoctype htmlhtml head title= title link(rel='stylesheet', href='/stylesheets/style.css') body h1= title p= content
通過res.render渲染
//app.jsvar 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])
用于對網(wǎng)頁模板進(jìn)行渲染
第一個參數(shù)是要渲染的模板名稱
第二個參數(shù)是傳遞給模板的變量,以對象形式存儲,沒有可省略
第三個參數(shù)是渲染后回調(diào)函數(shù),可以省略
路由
路由的意思就是根據(jù)不同的路徑,來指定不同的處理方法
我們一般把不同的路由封裝進(jìn)不同的模塊
首先在根目錄下創(chuàng)建一個文件夾routes存儲路由
現(xiàn)在我在routes文件夾下創(chuàng)建倆個路由文件index.js和users.js
修改app.js
//app.jsvar 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處理
下面簡單的實現(xiàn)一下路由
//routes/index.jsvar 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.jsvar express = require('express');var router = express.Router();router.get('/', function(req, res) { res.end('users');});module.exports = router;
通過express.Router()創(chuàng)建的router就像一個mini版的app一樣
app能做的,router都能做
只是我們把邏輯都封裝到了各個路由模塊中
上面代碼的結(jié)果:
body-parser中間件
作為一個入門級文章
最后就來淺顯的談一個中間件body-parser吧
其實express在3.x版本中內(nèi)置了很多中間件
但是4.x版本就將出static以外的所有中間件全部抽離出來了
所以就需要我們單獨安裝
對照表如下:
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請求有所不同
不同的地方就在于我們需要body-parser這個中間件來處理數(shù)據(jù)
通過req.body來獲得數(shù)據(jù)
首先使用前不要忘記下載
npm install body-parser --save
//app.jsvar 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('賬號: ' + user);});app.listen(3000);
下面這四個方法分別用于對body內(nèi)容采取不同的處理方法
這樣我首先通過get請求獲取主頁面
提交表單向服務(wù)器發(fā)送post請求
服務(wù)器響應(yīng)結(jié)果
express-generator
通過express-generator應(yīng)用生成器
可以為我們快速生成項目雛形
在你要生成項目的目錄中下載express-generator
npm install express-generator
然后輸入
express <項目文件名>
這樣express就會把必要的文件夾以及代碼快速生成了
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。
新聞熱點
疑難解答