以前一直使用 PHP+MySQL 做服務(wù)端的 API 服務(wù),后來用了 JavaScript 做前端開發(fā)后犯眠,發(fā)現(xiàn) JS 其實很好用谊娇,而且代碼庫非常豐富,尤其在云函數(shù)開發(fā)中使用了mongoDB后眶拉,更是欲罷不能千埃,所以決定后端也用 JS 來做開發(fā),并嘗試使用 mongoDB 作為數(shù)據(jù)庫忆植。后端 Node.js 開發(fā)很多都采用 express 來開發(fā) web 服務(wù)放可,所以我對在 express 中遇到的問題做了個學(xué)習(xí)筆記,以備自己查閱朝刊,也備同學(xué)們參考耀里!
1、安裝 express
首先在一個合適的位置建立目錄:express-demo拾氓;
在 windows 命令行界面(開始-運行-cmd)冯挎,運行 shell 命令:
cd express-demo
npm init -y ;; 初始化
npm install express --save ;; 安裝express
安裝完成!
2咙鞍、做一個最簡單的 express 網(wǎng)站
2.1织堂、創(chuàng)建服務(wù)主控文件
在當前目錄(express-demo)下叠艳,新建app.js文件:
/**
* 初始三部曲:引入、實例化易阳、端口
**/
const express = require(`express`) // 引入 express 模塊
const app = express() // 創(chuàng)建一個 express 應(yīng)用實例 app
const port = 3000 // 設(shè)置服務(wù)端口
//啟動監(jiān)聽
app.listen(port, () => {
console.log(`express is running at port ${port}!`)
})
這樣就建立了一個追簡單的 express web 服務(wù)器附较!
2.2、執(zhí)行 app.js 啟動 web 服務(wù)
node app.js
啟動完成潦俺!
在瀏覽器里輸入:http://127.0.0.1:3000拒课,會出現(xiàn)錯誤提示:Cannot GET /
這其實是很正常的,因為我們還沒有設(shè)置路由呢事示!
2.3早像、增加一個路由
修改 app.js,添加 Api 調(diào)用肖爵,使用 express 的 get 方法卢鹦,訪問業(yè)務(wù)模塊的對應(yīng)功能
app.get('/', (req, res) => res.send('index page!'))
修改后 app.js 整體源碼是這樣的:
/**
* 初始三部曲:引入、實例化劝堪、端口
**/
const express = require(`express`) // 引入 express 模塊
const app = express() // 創(chuàng)建一個 express 應(yīng)用實例 app
const port = 3000 // 設(shè)置服務(wù)端口
// 添加 Api 調(diào)用冀自,使用 express 的 get 方法,訪問業(yè)務(wù)模塊的對應(yīng)功能
app.get('/', (req, res) => res.send('index page!'))
//啟動監(jiān)聽
app.listen(port, () => {
console.log(`express is running at port ${port}!`)
})
修改 app.js 文件后秒啦,需要重啟服務(wù)才能起作用熬粗!在命令行窗口 ctrl+C 組合鍵停止 app.js 的運行,再重新運行:
node app.js
訪問 http://127.0.0.1:3000余境,訪問成功驻呐。
到此,一個最簡單的 web 服務(wù)器就搭起來了芳来,開發(fā)起來也很簡單吧含末?但功能也很有限不是,這只是個最基本操作步驟即舌,下面會繼續(xù)完善答渔!
2.4、【附加題】安裝 nodemon
有沒有發(fā)現(xiàn)每次修改源碼后侥涵,都要重啟服務(wù),是不是很麻煩宋雏?所以就裝一個專門的代碼監(jiān)控工具芜飘,當代碼變化時,自動重啟應(yīng)用磨总。這個工具就是nodemon嗦明,既然是 node 插件,安裝就必須很簡單了蚪燕,npm就可以:
npm install nodemon --save
安裝完成后娶牌,在命令行里奔浅,使用:nodemon app.js 來代替前面使用的:node app.js 即可!試試诗良,是不是很爽汹桦?
3、升級 -- 加入獨立的路由文件
3.1鉴裹、加入路由功能
上例中舞骆,app.get('/', (req, res) => res.send('index page!')),是 express 的 get 方法的使用径荔,不能算作是路由督禽。
而使用路由的模式,代碼更簡潔总处、模塊化更好狈惫,所以下面添加路由方法,在添加路由的過程中鹦马,會有很多變形胧谈。
在 app.js 文件里增加:
// 添加 users 路由器,路由到用戶管理模塊
const usersRouter = express.Router() // 創(chuàng)建一個子路由模塊 usersRouter
// 將路由器添加到應(yīng)用上,/users 是路由路徑,將路徑和子路由模塊 usersRouter 掛接起來
app.use('/users', usersRouter);
// usersRouter 的路由條目設(shè)置中符。注意這時候再加路由爪瓜,就可以不帶前面的/users路徑了
usersRouter.get('/', function (req, res) {
res.send('后臺獲取用戶列表數(shù)據(jù),并通過此接口返回');
});
在瀏覽器訪問:http://127.0.0.1:3000/users末融,顯示返回字符串:“后臺獲取用戶列表數(shù)據(jù),并通過此接口返回”,說明路由配置且工作正常键袱。
分析:新增的代碼有三行:
第一行:創(chuàng)建一個 Router
第二行:將 Router 掛接起來
第三行:增加路由映射,執(zhí)行業(yè)務(wù)邏輯
到此時摹闽,app.js 的整體代碼為:
/**
* 初始三部曲:引入蹄咖、實例化、端口
**/
const express = require(`express`) // 引入 express 模塊
const app = express() // 創(chuàng)建一個 express 應(yīng)用實例 app
const port = 3000 // 設(shè)置服務(wù)端口
// 添加 Api 調(diào)用付鹿,使用 express 的 get 方法澜汤,訪問業(yè)務(wù)模塊的對應(yīng)功能
app.get('/', (req, res) => res.send('index page!'))
// 添加 users 路由器,路由到用戶管理模塊
const usersRouter = express.Router() // 創(chuàng)建一個子路由模塊 usersRouter
// 將路由器添加到應(yīng)用上舵匾,/users 是路由路徑俊抵,將路徑和子路由模塊 usersRouter 掛接起來
app.use('/users', usersRouter);
// usersRouter 的路由條目設(shè)置。注意這時候再加路由坐梯,就可以不帶前面的/users路徑了
usersRouter.get('/', function (req, res) {
res.send('后臺獲取用戶列表數(shù)據(jù)徽诲,并通過此接口返回');
});
//啟動監(jiān)聽
app.listen(port, () => {
console.log(`express is running at port ${port}!`)
})
3.2、加入獨立的路由文件
上例中,userRouter 寫在 app.js 入口文件中谎替,這樣當路由增多時偷溺,app.js 文件會變得異常臃腫,所以考慮將模塊路由從 app.js 中獨立出來钱贯,只在 app.js 引用即可挫掏。
3.2.1、在項目根目錄下(和app.js 文件平級)建立 routers 目錄喷舀,在目錄下創(chuàng)建一個文件 users.js 砍濒,表示這是一個 users 相關(guān)的路由文件,內(nèi)容為:
const express = require('express'); // 導(dǎo)入 express 服務(wù)對象
const router = express.Router(); // 獲取 express 的路由對象
// 注意:下面的路由路徑為子路徑硫麻,此例中實際路徑需要加上前綴/users
router.get('/', (req, res) => {
res.send('users list page!')
})
router.get('/:id', (req, res) => {
res.send(`id 為:${req.params.id} 的用戶信息!`)
})
module.exports = router
3.2.2爸邢、修改 app.js 文件中的 路由定義和 use 語句,將
const userRouter = express.Router()
app.use('/users', userRouter)
userRouter.get('/', function(req, res){
res.send('后臺獲取用戶列表數(shù)據(jù)拿愧,并通過此接口返回')
})
修改為:
app.use('/users', require('./routers/users'))
測試運行杠河,沒有問題,這樣就成功把路由文件剝離出來了浇辜。
3.3券敌、加入 routers.js
按上面的做法,增加另外一個 router 柳洋,比如訂單路由: orders 待诅。
先增加路由文件 orders.js ,內(nèi)容如下:
const express = require('express'); // 導(dǎo)入 express 服務(wù)對象
const router = express.Router(); // 獲取 express 的路由對象
// 注意:下面的路由路徑為子路徑熊镣,此例中實際路徑需要加上前綴/orders
router.get('/', (req, res) => {
res.send('orders list page!')
})
router.get('/:id', (req, res) => {
res.send(`id 為:${req.params.id} 的訂單信息!`)
})
module.exports = router
同樣卑雁,還是需要修改 app.js 文件,需要加上一行:
app.use('/orders', require('./routers/orders'))
雖然不是很復(fù)雜绪囱,但每次增加路由模塊测蹲,都會修改 app.js ,感覺還是不爽鬼吵,還是需要升級扣甲,繼續(xù)變形看看...,具體做法就是
3.3.1齿椅、增加一個路由匯總定義文件: ./routers.js
var routers = function(app){
app.use('/users', require('./routers/users'))
app.use('/orders', require('./routers/orders'))
}
module.exports = routers
3.3.2琉挖、修改 app.js 文件
將 app.js 里的兩個對 /users 和 /orders 兩個路由的 use 語句刪除掉,增加一句涣脚,將路由匯總文件 routers.js 導(dǎo)入
require('./routers.js')(app) // app作為參數(shù)傳遞給 routers() 函數(shù)
至此示辈,對于路由的修改,基本就不用動 app.js 文件了涩澡,需要增加新的路由時,添加新的路由文件,并修改 ./router.js 的相應(yīng)內(nèi)容即可妙同。
備注:此例子中的 app.get('/',.....) 也可以改成路由器模式射富,再建立一個 indexRouter 就可以了,如果 index 的功能很簡單的話粥帚,index 部分不建立路由器胰耗,直接使用 express 的 get、post等方法也沒問題芒涡。
4柴灯、升級 -- 路由文件和業(yè)務(wù)分離
4、升級 -- 路由文件和業(yè)務(wù)分離
由前所述费尽,路由文件由 ./routers.js 匯總定義文件和 routers 目錄下的具體路由模塊文件組成赠群,路由結(jié)構(gòu)清晰多了,但目前路由模塊文件里還是涉及到很多的業(yè)務(wù)邏輯旱幼,能否將業(yè)務(wù)和路由剝離呢查描?經(jīng)測試,答案是肯定的柏卤。具體做法如下:
4.1冬三、在項目根目錄下建立文件夾 controllers
在此目錄下,為每個路由模塊建立一個控制器模塊缘缚,例如此例中的 users.js 和 orders.js:
users.js
var controller = {}
// list 方法對應(yīng) get('/users/',....) 路由
controller.list=function(req, res){
res.send('users list page!')
}
// info 方法對應(yīng) get('/users/:id',...) 路由
controller.info=function(req, res){
res.send(`id 為:${req.params.id} 的用戶信息!`)
}
module.exports = controller
orders.js
var controller = {}
// list 方法對應(yīng) get('/orders/',....) 路由
controller.list=function(req, res){
res.send('orders list page!')
}
// info 方法對應(yīng) get('/orders/:id',...) 路由
controller.info=function(req, res){
res.send(`id 為:${req.params.id} 的訂單信息!`)
}
module.exports = controller
4.2勾笆、修改子路由文件
修改路由模塊文件里的 router.get()方法,如下:
./routers/users.js
var controller = require('../controllers/users')
router.get('/', controller.list)
router.get('/:id', controller.info)
./routers/orders.js
var controller = require('../controllers/orders')
router.get('/', controller.list)
router.get('/:id', controller.info)
從上面的修改可以看出桥滨,路由模塊的引用很單純窝爪,除了模塊名稱不同、應(yīng)用文件不同该园,其他都差不多酸舍。而和邏輯有關(guān)的代碼都放到controllers下面去了,如果后面再加上數(shù)據(jù)模塊 models 里初,是不是和以前 PHP 的 MVC 很類似啃勉?這樣,express 和路由相關(guān)的架構(gòu)就基本確定双妨,后續(xù)就可以將重點放到邏輯代碼的開發(fā)上了淮阐。
后續(xù)如果有時間,會繼續(xù)研究一下數(shù)據(jù)模塊 models 的構(gòu)建模式刁品。