express看完还不会用?来打我!!!
express基本使用
背景
http模块
- 根据不同的请求路径、请求方法,做不同的事情,处理起来比较麻烦
- 读取请求体和写入请求体通过流的方式,比较麻烦
基本使用
- 安装express
npm i express
以下几个重要的模块可以与 express 框架一起安装:
- body-parser 用于处理 JSON, Raw, Text 和 URL 编码的数据。
- cookie-parser 解析Cookie的工具。通过req.cookies可以取到传过来的cookie,并把它们转成对象。
- multer 用于处理 enctype=“multipart/form-data”(设置表单的MIME编码)的表单数据。
- 引入express,创建一个express实例
const express = require('express');
const app = express();
- 监听端口
const port = 8080;
// param1 端口号
// param2 成功监听端口的回调
app.listen(port, () => {
console.log(`server litener on ${port}`);
});
- 监听请求
- 获取请求信息
// app[请求类型](param1: 请求路径, param2处理请求的回调)
app.get('/api/student/:id', (req, res) => {
console.log('get请求进来了')
// req 和 res 是express封装之后的对象
// 获取请求信息
console.log(req.headers) // 请求头
console.log("路径", req.path) // 完整请求路径(不包含query)
console.log("query", req.query) // query
console.log("params", req.params) // 路径参数
});
// get 请求 localhost:8080/api/student/001?name=qin
// req.path ---> /api/student/001
// req.query ---> { name: 'qin' }
// req.params ---> { id: '001' }
- 进行响应
app.get('/api/student/:id', (req, res) => {
console.log('get请求进来了')
// 设置响应头
// res.setHeader('a', '123');
// send会自动进行end()
// res.send([2, 3, 4]);
// 设置状态码 + 重定向 (可链式调用,每次执行方法返回的都是一个response对象)
// res.status(302).header("location", "https://ent.curtao.com").end();
// 重定向简写(状态码,重定向的地址)
res.redirect(302, "https://ent.curtao.com");
})
- 监听所有的get请求(建议放到最下方,所有get请求的路径找不到时,才执行)
app.get("*", (req, res) => {
console.log('任意get请求', req.path)
})
express中间件
一个express处理函数就是一个中间件
中间件处理细节
- 如果后续已经没有了中间件
- 当匹配到了请求后,交给第一个处理函数处理
- 函数中需要手动的交给后续中间件处理
// 两个参数req, res
// 三个参数req, res, next
// 四个参数err, req, res, next
// 此时路径是精确匹配
app.get('/api/student', (req, res, next) => {
console.log('中间件1');
next(); // 执行下一个中间件
}, (res, req) => {
console.log('中间件2');
});
错误处理中间件
- 如果在某一个中间件发生了错误(此处可手动抛出错误进行测试throw new Error('XXX'))
- 相当于调用了next(错误对象)
- 寻找后续的错误处理中间件,如果没有后续的错误处理中间件,则响应500。(express认为具有四个参数(err, req, res, next) => {}的中间为错误处理中间件)
// throw new Error('XXX') ---> next(new Error('XXX'))
// 四个参数
(err, req, res, next) => {} // --->错误处理中间件
// 此种方法使用中间件,只能匹配指定路径(/student)get请求发生的错误
app.get('/student', errorMiddleWare);
// 此种方法使用中间件,可以匹配所有路径get请求发生的错误
app.get('*', errorMiddleWare);
错误处理中间件一般放到最后,对所有请求的错误进行统一处理
app.use(’*’, errorMiddleWare); // 可匹配所有请求
// 这样使用中间件:可匹配/student, /student/XXX......路径下的所有请求
app.use('/student', errorMiddleWare);
响应静态页面的中间件express.static())
/*
* 下面这段代码的作用:
* 当请求时,会根据请求路径(req.path),从指定的目录中寻找是否存在该文件,
* 如果存在,直接响应文件内容,而不再移交给后续的中间件
* 如果不存在文件,则直接移交给后续的中间件处理
* 默认情况下,如果映射的结果是一个目录,则会自动使用index.html文件
*/
const staticRoot = path.resolve(__dirname, "../dist");
app.use(express.static(staticRoot));
express解析body请求体
body在node中需要用流的方式读取,express提供了解析消息体的中间件
1. express.urlencoded({extended: true, …}) // 使用qs库进行解析
- 解析请求头的Content-Type为application/x-www-form-urlencoded的请求体
2. express.json([options])
- 解析请求头的Content-Type为application/json的请求体
express路由
// student.js
const express = require("express");
const router = express.Router();
router.get('/', (req, res) => {
res.send('获取所有学生');
});
router.get('/:id', (req, res) => {
res.send('获取单个学生');
});
router.post('/', (req, res) => {
res.send('添加一个学生');
});
router.delete('/:id', (req, res) => {
res.send('删除一个学生');
});
router.put('/:id', (req, res) => {
res.send('修改一个学生');
});
module.exports = router;
// index.js
// 处理 api 的请求, 所有基地址为/api/student的请求, 都会通过此路由进行处理
app.use('/api/student', require("./api/student"));
服务端发送http请求报错的统一处理函数
// 获取单个学生
router.get('/:id', async (req, res) => {
// 此处使用Promise模拟http请求中的报错
const result = await new Promise((resolve, reject) => {
throw new Error('http请求发生错误');
});
res.send(result);
});
// 常规解决方法
router.get('/:id', async (req, res) => {
try {
const result = await new Promise((resolve, reject) => {
throw new Error('http请求发生错误');
});
res.send(result);
} catch (error) {
next(error);
}
});
// 可抽取公共方法来统一处理异步错误
// 统一处理异步错误的方法
const asyncHandler = (handler) => {
return async (req, res, next) => {
try {
const result = await handler(req, res, next);
res.send(result);
} catch (error) {
next(error);
}
};
}
router.get('/:id', asyncHandler(async (req, res, next) => {
// 获取单个学生的http请求
return await new Promise((resolve, reject) => {
throw new Error('http请求发生错误');
});
}));