本章主要講什么(一句話)兴蒸?
《項目實戰(zhàn):基于Angular2+Mongodb+Node技術實現(xiàn)的多用戶博客系統(tǒng)教程(5)》
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?-- Express框架代碼培析&優(yōu)化配置
一上枕、前言
? ? ?上一章,我們給大家講解了項目實戰(zhàn)所必須的基礎環(huán)境搭建與必備知識儲備技能,同時對Express框架進行了快速搭建荡灾,本章我們將會對Express框架給大家做一個詳細的培析,同時對本框架結(jié)合我們的項目需求做一優(yōu)化重構(gòu)哮内。
PS--不過后繼想改變一下嚴肅的風格圈暗,采用一些好玩的圖片配合,希望能讓枯燥的編程能夠產(chǎn)生點樂趣 :)
二缘挽、Express框架詳解
2.1瞄崇、工程結(jié)構(gòu)
2.1.1、工程結(jié)構(gòu)-工程目錄
生成的工程目錄里面都有什么壕曼,打開我們的blog文件夾苏研,里面如圖所示:
說明如下:
app.js:啟動文件,或者說入口文件
package.json:存儲著工程的信息及模塊依賴腮郊,當在dependencies中添加依賴的模塊時摹蘑,運行npm install,npm會檢查當前目錄下的package.json伴榔,并自動安裝所有指定的模塊
node_modules:存放package.json中安裝的模塊纹蝴,當你在package.json添加依賴的模塊并安裝后,存放在這個文件夾下
public:存放image踪少、css塘安、js等文件
routes:存放路由文件
views:存放視圖文件或者說模版文件
bin:存放可執(zhí)行文件
2.1.2、工程結(jié)構(gòu)-app.js
打開app.js,讓我們看看里面究竟有什么:
核心代碼我以注釋的方式解釋援奢!
// require()加載了express兼犯、path等模塊,以及routes文件夾下
//的index. js和users.js路由文件
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();//生成一個express實例app。
/*設置views文件夾為存放視圖文件的目錄,即存放模板文件的地方
,__dirname為全局變量,存儲當前正在執(zhí)行的腳本所在的目錄集漾。*/
app.set('views', path.join(__dirname, 'views'));
//設置視圖模板引擎為ejs
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//設置/public/favicon.ico為favicon圖標切黔。
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev')); //加載日志中間件
app.use(bodyParser.json()); //加載解析json的中間件
app.use(bodyParser.urlencoded({ extended: false })); //加載解析urlencoded請求體的中間件
app.use(cookieParser()); //加載解析cookie的中間件
app.use(express.static(path.join(__dirname, 'public'))); //設置public文件夾為存放靜態(tài)文件的目錄。
//路由控制器
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
//捕獲404錯誤具篇,并轉(zhuǎn)發(fā)到錯誤處理器
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
//開發(fā)環(huán)境下的錯誤處理器纬霞,將錯誤信息渲染error模版并顯示到瀏覽器中
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
//生產(chǎn)環(huán)境下的錯誤處理器,將錯誤信息渲染error模版并顯示到瀏覽器中
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
//導出app實例供其他模塊調(diào)用
module.exports = app;
2.1.3驱显、工程結(jié)構(gòu)-bin/www文件
打開bin目錄下的www文件诗芜,內(nèi)容如下:
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('blog:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
瞳抓。。伏恐。孩哑。
上述代碼解釋如下:
(1) #!/usr/bin/env node:表明是node可執(zhí)行文件。
(2) var debug =require('debug')('blog:server')
:引入debug模塊翠桦,打印調(diào)試日志横蜒。
(3) var app = require('../app’):引入我們上面導出的app實例。
(4) app.set('port', process.env.PORT || 3000):設置端口號销凑。
(5) var server = http.createServer(app); server.listen(port);
server.on('error', onError); server.on('listening',onListening);
啟動工程并監(jiān)聽3000端口
2.1.4丛晌、工程結(jié)構(gòu)-routes/index.js文件
再看routes/index.js文件:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
生成一個路由實例用來捕獲訪問主頁的GET請求,導出這個路由并在app.js中通過app.use('/', routes);加載闻鉴。這樣茵乱,當訪問主頁時,就會調(diào)用res.render('index', { title: 'Express' });渲染views/index.ejs模版并顯示到瀏覽器中孟岛。
我們再看看views/index.ejs文件:
在渲染模板時我們傳入了一個變量title值為express字符串瓶竭,模板引擎會將所有<%= title %>替換為express,然后將渲染后生成的html顯示到瀏覽器中渠羞,如上圖所示
至此斤贰,我們知道了如何創(chuàng)建一個Express工程并啟動它,了解了工程的大體結(jié)構(gòu)和運作流程!
2.2次询、路由控制
2.2.1荧恍、工作原理
routes/index.js中有以下代碼:
router.get('/', function(req, res){
res.render('index', { title: 'Express' });
});
這段代碼的意思是當訪問主頁時,調(diào)用ejs模板引擎屯吊,來渲染index.ejs模版文件(即將title變量全部替換為字符串Express)送巡,生成靜態(tài)頁面并顯示在瀏覽器中。
我們來作一些修改盒卸,以上代碼實現(xiàn)了路由的功能骗爆,我們當然可以不要routes/index.js文件,把實現(xiàn)路由功能的代碼都放在app.js里蔽介,但隨著時間的推移app.js會變得臃腫難以維護摘投,這也違背了代碼模塊化的思想,所以我們把實現(xiàn)路由功能的代碼都放在routes/index.js里虹蓄。官方給出的寫法是在app.js中實現(xiàn)了簡單的路由分配犀呼,然后再去index.js中找到對應的路由函數(shù),最終實現(xiàn)路由功能薇组。我們不妨把路由控制器和實現(xiàn)路由功能的函數(shù)都放到index.js里外臂,app.js中只有一個總的路由接口。
最終將app.js修改為:
PS:注意加粗部分律胀!
……
var http = require('http');
……
var routes = require('./routes/index');
var app = express();
app.set('port', process.env.PORT || 3000);
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
….
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
routes(app);
http.createServer(app).listen(app.get('port'),function(){
console.log('服務器已啟動专钉,監(jiān)聽端口:%s',app.get('port'));
});
//app.use('/', routes);
//app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
…..
<%= title %>
修改index.js如下:
module.exports = function(app) {
app.get('/', function (req, res) {
res.render('index', { title: 'Express' });
});
};
現(xiàn)在挑童,再運行你的app累铅,你會發(fā)現(xiàn)主頁毫無二致跃须。這里我們在routes/index.js中通過module.exports導出了一個函數(shù)接口,在app.js中通過require加載了index.js然后通過routes(app)調(diào)用了index.js導出的函數(shù)娃兽。
同時刪除掉:bin目錄及目錄下的www文件
2.2.2菇民、路由規(guī)則
? 通過Requre獲取數(shù)據(jù)
express封裝了多種http請求方式,我們主要只使用get和post兩種投储,即app.get()和app.post()第练。
app.get()和app.post()的第一個參數(shù)都為請求的路徑,第二個參數(shù)為處理請求的回調(diào)函數(shù)玛荞,回調(diào)函數(shù)有兩個參數(shù)分別是req和res娇掏,代表請求信息和響應信息 。路徑請求及對應的獲取路徑有以下幾種形式:
方式一勋眯、req.query
// GET /search?q=fwytech+ferret
req.query.q
// => "fwytech ferret"
// GET /shoes?order=desc&color=blue& type=converse
req.query.order
// => "desc"
req.query.shoe.color
// => "blue"
req.query.shoe.type
// => "converse"
方式二婴梧、req.body
// POST user[name]=fwytech&user[email]=fwytech@126.com
req.body.user.name
// => "fwytech"
req.body.user.email
// => "fwytech@126.com"
// POST { "name": "fwytech" }
req.body.name
// => "fwytech"
方式三、req.params
// GET /user/tj
req.params.name
// => "tj"
// GET /file/javascripts/jquery.js
req.params[0]
// => "javascripts/jquery.js"
方式四客蹋、req.param(name)
// ?name=tobi
req.param('name')
// => "tobi"
// POST name=tobi
req.param('name')
// => "tobi"
// /user/tobifor/user/:name
req.param('name')
// => "tobi"
不難看出:
·req.query: 處理get請求塞蹭,獲取get請求參數(shù)
·req.params: 處理/:xxx形式的get或post請求,獲取請求參數(shù)
·req.body: 處理post請求讶坯,獲取post請求體
·req.param(): 處理get和post請求番电,但查找優(yōu)先級由高到低為req.params→req.body→req.query
路徑規(guī)則還支持正則表達式,更多請查閱:http://expressjs.com/en/api.html
2.2.3辆琅、路由規(guī)則添加路由規(guī)則
請在Node命令提示符下將目錄定位至你的node-blog目錄下:
> node app
啟動node服務器!
再次打開瀏覽器:健入http://localhost:3000,如果一切正常將會顯示如下:
當我們訪問localhost:3000/hello這種不存在的頁面時就會顯示:
這是因為不存在/hello的路由規(guī)則漱办,而且它也不是一個public目錄下的文件,所以express返回了404 Not Found的錯誤婉烟。下面我們來添加這條路由規(guī)則娩井,使得當訪問localhost:3000/hello時,頁面顯示hello,world!
注意:以下修改僅用于測試隅很,看到效果后再把代碼還原回來撞牢。
修改index.js,在app.get('/')函數(shù)后添加一條路由規(guī)則:
app.get('/hello', function (req, res) {
res.send('hello,world!');
});
重啟之后叔营,訪問localhost:3000/hello頁面顯示如下:
三屋彪、后述
? ?《基于Angular2+Mongodb+Node技術實現(xiàn)的多用戶博客系統(tǒng)》正在連載中,明天我將為大家推出【第六章:項目需求分析&路由歸劃&MongoDB配置】绒尊,歡迎各位繼續(xù)關注~
? ? 搜索并關注“風舞煙”的簡書專欄畜挥、頭條號、微信公眾號婴谱、 企鵝媒體平臺蟹但,你可以定期收到關于簡書專欄的最新動態(tài)以及IT前沿最新技術的高質(zhì)量經(jīng)驗文章躯泰、視頻分享。
? ? 謝謝大家的支持华糖,歡迎大家留言交流麦向。
本章代碼下載:http://pan.baidu.com/s/1nu6EIMH