以前一直使用 PHP+MySQL 做服务端的 API 服务,后来用了 JavaScript 做前端开发后,发现 JS 其实很好用,而且代码库非常丰富,尤其在云函数开发中使用了mongoDB后,更是欲罢不能,所以决定后端也用 JS 来做开发,并尝试使用 mongoDB 作为数据库。后端 Node.js 开发很多都采用 express 来开发 web 服务,所以我对在 express 中遇到的问题做了个学习笔记,以备自己查阅,也备同学们参考!
1、安装 express
首先在一个合适的位置建立目录:express-demo;
在 windows 命令行界面(开始-运行-cmd),运行 shell 命令:
cd express-demo
npm init -y ;; 初始化
npm install express --save ;; 安装express
安装完成!
2、做一个最简单的 express 网站
2.1、创建服务主控文件
在当前目录(express-demo)下,新建app.js文件:
/**
* 初始三部曲:引入、实例化、端口
**/
const express = require(`express`) // 引入 express 模块
const app = express() // 创建一个 express 应用实例 app
const port = 3000 // 设置服务端口
//启动监听
app.listen(port, () => {
console.log(`express is running at port ${port}!`)
})
这样就建立了一个追简单的 express web 服务器!
2.2、执行 app.js 启动 web 服务
node app.js
启动完成!
在浏览器里输入:http://127.0.0.1:3000,会出现错误提示:Cannot GET /
这其实是很正常的,因为我们还没有设置路由呢!
2.3、增加一个路由
修改 app.js,添加 Api 调用,使用 express 的 get 方法,访问业务模块的对应功能
app.get('/', (req, res) => res.send('index page!'))
修改后 app.js 整体源码是这样的:
/**
* 初始三部曲:引入、实例化、端口
**/
const express = require(`express`) // 引入 express 模块
const app = express() // 创建一个 express 应用实例 app
const port = 3000 // 设置服务端口
// 添加 Api 调用,使用 express 的 get 方法,访问业务模块的对应功能
app.get('/', (req, res) => res.send('index page!'))
//启动监听
app.listen(port, () => {
console.log(`express is running at port ${port}!`)
})
修改 app.js 文件后,需要重启服务才能起作用!在命令行窗口 ctrl+C 组合键停止 app.js 的运行,再重新运行:
node app.js
访问 http://127.0.0.1:3000,访问成功。
到此,一个最简单的 web 服务器就搭起来了,开发起来也很简单吧?但功能也很有限不是,这只是个最基本操作步骤,下面会继续完善!
2.4、【附加题】安装 nodemon
有没有发现每次修改源码后,都要重启服务,是不是很麻烦?所以就装一个专门的代码监控工具,当代码变化时,自动重启应用。这个工具就是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() // 创建一个子路由模块 usersRouter
// 将路由器添加到应用上,/users 是路由路径,将路径和子路由模块 usersRouter 挂接起来
app.use('/users', usersRouter);
// usersRouter 的路由条目设置。注意这时候再加路由,就可以不带前面的/users路径了
usersRouter.get('/', function (req, res) {
res.send('后台获取用户列表数据,并通过此接口返回');
});
在浏览器访问:http://127.0.0.1:3000/users,显示返回字符串:“后台获取用户列表数据,并通过此接口返回”,说明路由配置且工作正常。
分析:新增的代码有三行:
第一行:创建一个 Router
第二行:将 Router 挂接起来
第三行:增加路由映射,执行业务逻辑
到此时,app.js 的整体代码为:
/**
* 初始三部曲:引入、实例化、端口
**/
const express = require(`express`) // 引入 express 模块
const app = express() // 创建一个 express 应用实例 app
const port = 3000 // 设置服务端口
// 添加 Api 调用,使用 express 的 get 方法,访问业务模块的对应功能
app.get('/', (req, res) => res.send('index page!'))
// 添加 users 路由器,路由到用户管理模块
const usersRouter = express.Router() // 创建一个子路由模块 usersRouter
// 将路由器添加到应用上,/users 是路由路径,将路径和子路由模块 usersRouter 挂接起来
app.use('/users', usersRouter);
// usersRouter 的路由条目设置。注意这时候再加路由,就可以不带前面的/users路径了
usersRouter.get('/', function (req, res) {
res.send('后台获取用户列表数据,并通过此接口返回');
});
//启动监听
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 目录,在目录下创建一个文件 users.js ,表示这是一个 users 相关的路由文件,内容为:
const express = require('express'); // 导入 express 服务对象
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('后台获取用户列表数据,并通过此接口返回')
})
修改为:
app.use('/users', require('./routers/users'))
测试运行,没有问题,这样就成功把路由文件剥离出来了。
3.3、加入 routers.js
按上面的做法,增加另外一个 router ,比如订单路由: orders 。
先增加路由文件 orders.js ,内容如下:
const express = require('express'); // 导入 express 服务对象
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'))
虽然不是很复杂,但每次增加路由模块,都会修改 app.js ,感觉还是不爽,还是需要升级,继续变形看看...,具体做法就是
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 导入
require('./routers.js')(app) // app作为参数传递给 routers() 函数
至此,对于路由的修改,基本就不用动 app.js 文件了,需要增加新的路由时,添加新的路由文件,并修改 ./router.js 的相应内容即可。
备注:此例子中的 app.get('/',.....) 也可以改成路由器模式,再建立一个 indexRouter 就可以了,如果 index 的功能很简单的话,index 部分不建立路由器,直接使用 express 的 get、post等方法也没问题。
4、升级 -- 路由文件和业务分离
4、升级 -- 路由文件和业务分离
由前所述,路由文件由 ./routers.js 汇总定义文件和 routers 目录下的具体路由模块文件组成,路由结构清晰多了,但目前路由模块文件里还是涉及到很多的业务逻辑,能否将业务和路由剥离呢?经测试,答案是肯定的。具体做法如下:
4.1、在项目根目录下建立文件夹 controllers
在此目录下,为每个路由模块建立一个控制器模块,例如此例中的 users.js 和 orders.js:
users.js
var controller = {}
// list 方法对应 get('/users/',....) 路由
controller.list=function(req, res){
res.send('users list page!')
}
// info 方法对应 get('/users/:id',...) 路由
controller.info=function(req, res){
res.send(`id 为:${req.params.id} 的用户信息!`)
}
module.exports = controller
orders.js
var controller = {}
// list 方法对应 get('/orders/',....) 路由
controller.list=function(req, res){
res.send('orders list page!')
}
// info 方法对应 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)
从上面的修改可以看出,路由模块的引用很单纯,除了模块名称不同、应用文件不同,其他都差不多。而和逻辑有关的代码都放到controllers下面去了,如果后面再加上数据模块 models ,是不是和以前 PHP 的 MVC 很类似?这样,express 和路由相关的架构就基本确定,后续就可以将重点放到逻辑代码的开发上了。
后续如果有时间,会继续研究一下数据模块 models 的构建模式。
网友评论