简介
Express是一个基于Node平台的web应用开发框架,提供一系列强大特性,帮助你创建各种 Web应用。
框架特性
-
提供了方便简洁的路由定义方式
-
对获取HTTP请求参数进行了简化处理
-
对模板引擎支持程度高,方便渲染动态HTML页面
-
提供了中间件机制有效控制HTTP请求
-
拥有大量第三方中间件对功能进行扩展
安装
npm install express
初体验
- 路由定义更简单
- app.get
- app.post
- 获取请求参数更简单
- get:req.query
- post:req.body
- express中不再使用res.end方法响应客户端,取而代之的是res.send方法
- res.send方法内部也会调用res.end方法
- 可以自动设置HTTP状态码
- 可以自动检测响应内容类型并设置上去
- 自动设置编码格式
- 直接发送一个JSON对象
范例:
// 引入Express框架
const express = require('express')
// 使用框架创建web服务器
const app = express()
// 程序监听3000端口
app.listen(3000)
// 当客户端以get方式访问/路由时
app.get('/', (req, res) => {
// 对客户端做出响应 send方法会根据内容的类型自动设置请求头
res.send('Hello Express')
})
路由
Express框架对路由功能进行了封装,提供了get、post、delete、put等方法,使得定义路由非常简便。
app.get('/', (req, res) => {
// 对客户端做出响应
res.send('Hello Express')
})
// 当客户端以post方式访问/add路由时
app.post('/add', (req, res) => {
res.send('使用post方式请求了/add路由')
})
模块化路由
将一类路由定义到一个模块中,方便管理维护
const express = require('express')
const app = express()
const { userRouter } = require('./routes/user')
// 当拦截到 /user 开头请求时,交给 userRouter 处理
app.use('/user', userRouter)
app.listen(3000)
console.log('服务启动成功')
抽离成单独js文件存放,用 module.exports
导出即可
const express = require('express')
const userRouter = express.Router()
// /user/index
userRouter.get('/index', (req, res) => {
res.send('用户首页')
})
// /user/reg
userRouter.get('/reg', (req, res) => {
res.send('用户注册页')
})
module.exports = { userRouter }
路由参数
路由参数(占位符)(RestFul风格的URL)(推荐)
app.get('/index/:name/:age', (req, res) => {
console.log(req.params) // { name: 'zs', age: 18 }
res.send('ok')
})
tip:参数个数不能多,不能少,否则匹配不上路由
请求
GET
如果没有GET参数,req.query
是一个空对象 {}
,并不是 null
或 undefined
,所以在逻辑判断的时候要小心
// http://localhost:3000/index?name=zhangsan&age=18
app.get('/index', (req, res) => {
console.log(req.query) // { name: 'zhangsan', age: 18 }
res.send('ok')
})
POST
- Express中接收post请求参数需要借助第三方包
body-parser
- bodyParser.urlencoded方法的参数的extended是一个必填项
- 如果是false,那么就用系统模块querystring来解析请求参数
- 如果是true,那么就用第三方模块qs来解析请求参数
- 从功能性上来讲,qs比querystring要强大,所以我们可以根据实际项目来指定
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false }))
// POST http://localhost:3000/add
app.post('/add', (req, res) => {
console.log(req.body) // { name: 'zhangsan', age: 18 }
res.send('ok')
})
中间件
- 中间件本质上就是函数,可访问请求对象和响应对象,可对请求进行拦截处理,处理后再将控制权向下传递,也可终止请求,向客户端做出响应 (可以理解为请求的拦截器)
- 中间件有两部分组成:
- 定义中间件的方法:由Express提供
- 中间件处理函数:有程序员编写
- 中间件可以有多个,先定义的先进入(满足条件的情况下),可以调用next方法交给下一个中间件,直到遇到结束请求的中间件
使用方法
调用 app.use()
定义中间件
-
该方法可以传递一个函数作为参数,表示任何任何请求都会经过该中间件,都会执行该参数内部的代码。
app.use((req, res, next) => { next() })
- 中间件函数有三个参数,分别为请求对象req、响应对象res、释放控制权方法next
- 中间件函数中的代码执行完成之后需要调用
next()
方法,才能开始执行下一个中间件,否则请求将挂起
-
该方法的第一个参数也可以是请求路径,表示只有该请求路径才会经过该中间件。
app.use('/pathname', (req, res, next) => { next() })
tip: 可以用做网站维护公告或登录拦截
自定义404页面
自定义404页面,可以通过 res.status(404)
方法来设置HTTP状态码
// 处理用户访问路径出错的情况
app.get('*', (req, res) => res.render('error.html'));
// 此中间件一定要写在程序的最后 其他路径都匹配不成功时再匹配404页面
tip:res.send和next后,如果还有代码,是会执行的,所以我们一般都会在方法前加个return,阻止后续代码执行
错误处理
Express默认会把程序错误信息输出到页面中,在开发阶段有助于开发人员观察错误信息,但是在项目发布以后是不希望用户看到这些错误信息的,所以可以使用Express提供的错误处理中间件处理错误信息。
- 同步代码抛错:
throw new Error(message)
- 异步代码抛错:
next(new Error(message))
,异步代码只能通过这种方式抛出去错误才能被错误处理中间件捕获到 - 错误处理中间件一般定义在最后
app.use((err, req, res, next)=>{
// 在控制台中输出错误信息
console.error(err.message);
// 对客户端做出响应
res.status(500).send(err.message);
});
异步函数错误捕获
try
、catch
关键字可以捕获程序在运行过程中发生的错误,形如:
try {
await User.find()
} catch(err) {
next(err)
}
----------------------------------------
await User.find().catch(err => next(err)) // 推荐用
tip:try … catch 只能捕获同步错误和异步函数错误,不能捕获其他异步API抛出的错误,比如:
setTimeout
、fs.readFile('some.file', 'utf8', (err, data) => { if (err) { throw err } })
静态资源访问
通过 Express 内置的 express.static
可以方便地托管静态文件,例如图片、CSS、JavaScript 文件等
const express = require('express')
const path = require('path')
const app = express()
// 用path.join拼接成绝对路径,指定静态资源根目录
// 所有请求都会优先走这个中间件,如果能找到匹配的静态资源,那么就返回,如果找不到,就调用next()交给下一个中间件去处理
app.use(express.static(path.join(__dirname, 'public')))
// 一般命名为public或static
app.use('/static' , express.static(path.join(__dirname, 'public'))) // 推荐用这种形式 优化性能 避免处理不必要的请求
app.listen(3000)
配置模板引擎
- Express框架没有内置模板引擎,但是对其他模板引擎提供了良好的支持,比如
art-template
- 我在这使用了
express-art-template
第三方模块,实际上内部也是基于art-template
来实现的,只不过为了更好的支持express框架来做了一些额外的处理,语法还是art-template
的,所以安装时需要装两个 - 安装
npm install express-art-template art-tempalte
// utils/art-template.js 封装
const path = require('path')
const artTemplate = require('express-art-template')
module.exports = {
artTemplate: (app) => {
// 指定用artTemplate模板引擎去解析.html后缀的模板
// 理论上来讲,是可以同时存在多个模板引擎的,但是一般情况下,项目里面只会用一个模板引擎
app.engine('html', artTemplate)
// 指定模板文件的根目录
app.set('views', path.join(__dirname, 'views'))
// 指定模板文件的默认后缀为html
app.set('view engine', 'html')
}
}
app.js:
const { artTemplate } = require('./utils/art-template')
artTemplate(app)
app.get('/index', (req, res) => {
res.render('index', { name: 'zs', age: 18 })
// 1. 会自动去模板文件的根目录下查找名为index的模板文件
// 2. 会自动拼接模板默认后缀名
// 3. 会自动结合模板数据解析模板
// 4. 会自动将模板引擎解析出来的最终HTML响应给客户端,所以我们不需要再调用res.send和res.end方法了
})
Locals对象
app.locals
对象中的键值对在所有的模板文件中都能拿到,以键值对的形式存在,一般我们用来存放公共的数据- 语法:
app.locals.key = value
app.use('/admin', async (req, res, next) => {
app.locals.users = await User.find()
next()
})