目录
一、简介
Express是基于Node.js平台,快速、开发、极简的Web开发框架。实际上是npm上的第三方包,提供了快速创建Web服务器的便捷方法。
二、基本使用
1. 安装
npm i express@4.17.2
2. 创建基本的Web服务器
2.1 创建web服务器
//导入express
const express = require('express');
//创建web服务器
const app = express();
//启动web服务器
app.listen(80,()=>{
console.log('express server is running at http://127.0.0.1');
})
2.2 监听GET与POST请求
app.get('/shop', (req, res) => {
//调用express提供的res.send(),向客户端响应一个JSON对象
res.send({ name: 'zs', age: 20, gender: '男' });
})
app.post('/login', (req, res) => {
res.send('请求成功!');
})
2.3 获取URL中携带的查询参数
app.get('/', (req, res) => {
console.log(req.query);
res.send(req.query);
})
//通过req.params对象,可以访问到URL中通过:匹配到的动态参数
app.get('/user/:id/:name', (req, res) => {
console.log(req.params);
res.send(req.params);
})
2.4 托管静态资源
通过express.static(),我们可以创建一个静态资源服务器。例如,将 assets 目录下的图片、CSS文件、JaveScript文件对外开放访问。
注意:此时访问路径中不要加/assets
app.use(express.static('./re_assets'));
app.use(express.static('./assets'));
补充:如果希望在托管的静态资源访问路径之前挂载路径前缀,则可用:
app.use('/assets',express.static('./assets'));
// 访问路径变为:http://127.0.0.1/assets/index.html
2.5 小工具 nodemon
作用:能够监听项目文件的变动,当代码被修改后,nodemon会帮助我们重启项目,方便开发与调试。
安装:npm i -g nodemon
使用:nodemon test.js
三、Express 路由
1. 最简单的用法
const express = require('express');
const app = express();
// 挂载路由
app.get('/', (req, res) => {
res.send('Get Request!');
})
app.post('/', (req, res) => {
res.send('Post Request!');
})
app.listen(80, () => {
console.log('express server is running at http://127.0.0.1');
})
2. 模块化路由
原因:为方便对路由进行模块化管理,Express不建议将路由直接挂载到app上,而是推荐将路由抽离为单独的模块。
步骤如下:
a. 创建路由模块对应的js文件
b. 调用express.Router()函数创建路由对象
c. 向路由对象上挂载具体的路由
d. 使用module.exports向外共享路由对象
e. 使用app.use()函数注册路由模块
router.js
const express = require('express');
const router = express.Router();
router.get('/content/list',(req,res)=>{
res.send('Get content list!');
})
router.post('/content/add',(req,res)=>{
res.send('Add new content!');
})
module.exports = router;
index.js
const express = require('express');
const app = express();
const router = require('./03.router');
// app.use(router);
app.use('/api', router); //访问路径要加上/api
app.listen(80, () => {
console.log('express server is running at http://127.0.0.1');
})
四、Express 中间件
中间件,指业务流程的中间处理环节。当一个请求到达Express的服务器后,可以连续调用多个中间件,从而对这次请求进行预处理。
注意:中间件函数的形参列表中,必须包含next参数。而路由处理函数只包含req与res。next()函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由。
1. 全局生效的中间件
客户端发起的任何请求,到达服务器后,都会被触发的中间件叫做全局生效的中间件。
通过app.use(中间件函数),即可定义一个全局生效的中间件。
const express = require('express');
const app = express();
const mw = function (req, res, next) {
console.log('最简单的中间件');
//把流转关系,转交给下一个中间件或是路由
next();
}
//将mw注册为全局生效的中间件
app.use(mw);
app.get('/',(req,res)=>{
console.log('调用了 / 路由');
res.send('Get Request');
})
app.post('/',(req,res)=>{
res.send('Post Request');
})
app.listen(80, () => {
console.log('express server is running at http://127.0.0.1');
})
2. 定义全局中间件的简化形式
app.use((req, res, next) => {
console.log('这是最简单的中间件函数');
next();
})
3. 中间件的作用
多个中间件之间,共享同一份req和res。基于这样的特性,我们可以在上游的中间件中,统一为req或res对象添加自定义的属性或方法,供下游的中间件或路由来使用。
const express = require('express');
const app = express();
app.use((req, res, next) => {
const time = Date.now();
//为req对象挂载自定义属性,以便把时间共享给后面的所有路由
req.startTime = time;
next();
})
app.get('/', (req, res) => {
res.send('Get Request' + req.startTime);
})
app.post('/', (req, res) => {
res.send('Post Request' + req.startTime);
})
app.listen(80, () => {
console.log('express server is running at http://127.0.0.1');
})
4. 定义多个全局中间件
const express = require('express');
const app = express();
app.use((req,res,next)=>{
console.log('调用第一个全局中间件');
next();
})
app.use((req,res,next)=>{
console.log('调用第二个全局中间件');
next();
})
app.get('/',(req,res)=>{
res.send('Get Request!');
})
app.listen(80,()=>{
console.log('express server is running at http://127.0.0.1');
})
5. 局部生效的中间件
不使用app.use()定义的中间件
const express = require("express");
const app = express();
const mw1 = (res, req, next) => {
console.log('调用第一个局部生效的中间件');
next();
}
const mw2 = (res, req, next) => {
console.log('调用第二个局部生效的中间件');
next();
}
app.get('/', (req, res) => {
res.send('Get Request!');
})
// 或者[mw1,mw2]这样写也可以
app.get('/home', mw1, mw2, (req, res) => {
res.send('Home Page!');
})
app.listen(80, () => {
console.log('express server is running at http://127.0.0.1');
})
6. 注意事项
a. 一定要在路由前注册中间件(因为是由上到下的过程)
b. 客户端发送过来的请求可以连续调用多个中间件进行处理
c. next()函数不要忘记去调用
d. 在next()函数后不要再写代码了(防止逻辑混乱)
e. 连续调用多个中间件时,多个中间件共享req和res对象
7. 中间件的分类
(1)应用级别的中间件:绑定到app实例上的中间件,如app.use()等
(2)路由级别的中间件:绑定到express.Router()实力上的中间件,如router.use()
(3)错误级别的中间件:用来捕获项目中发生的异常错误,从而防止项目异常崩溃的问题。
错误级别中间件的function中必须按顺序有:err,req,res,next
(4)Express内置的中间件:
a. express.static():快速托管静态资源
b. express.json():解析JSON格式的请求体数据(4.16.0+ version)c. express.urlencoded():解析URL-encoded格式的请求体数据(4.16.0+ version)
(5)第三方的中间件
错误级别中间件演示:(注意:错误级别的中间件必须注册在所有路由之后!)
const express = require('express');
const app = express();
app.get('/', (req, res) => {
//人为抛出一个错误
throw new Error('服务器发生错误');
res.send('Get Request');
})
app.use((err, req, res, next) => {
console.log('发生了错误' + err.message);
res.send('Error:' + err.message);
next();
})
app.listen(80, () => {
console.log('express server is running at http://127.0.0.1');
})
express.json()用法演示:
const express = require('express');
const app = express();
//通过express.json()中间件,解析表单中JSON格式的数据
app.use(express.json());
app.post('/',(req,res)=>{
// 使用req.body来接收客户端发送过来的请求体数据
// 默认情况下,如果不配置解析表单数据的中间件,则为undefined
console.log(req.body);
res.send('Post Request!');
})
app.listen(80,()=>{
console.log('express server is running at http://127.0.0.1');
})
express.urlencoded()用法演示:
const express = require('express');
const app = express();
//通过express.urlencoded()这个中间件,来解析表单中的url-encoded格式的数据
app.use(express.urlencoded({extended:false}));
app.post('/',(req,res)=>{
console.log(req.body);
res.send('Post Request!');
})
app.listen(80,()=>{
console.log('express server is running at http://127.0.0.1');
})
第三方中间件演示:
npm i body-parser
const express = require('express');
const app = express();
const parser = require('body-parser');
app.use(parser.urlencoded({extended:false}));
app.post('/',(req,res)=>{
console.log(req.body);
res.send('ok');
})
app.listen(80,()=>{
console.log('express server is running at http://127.0.0.1');
})
五、应用-自定义解析表单数据的中间件
1. 创建自定义的模块:custom-body-parser.js
const qs = require('querystring'); // Node.js只的内置模块
const bodyParser = (req, res, next) => {
let str = ''; // 用来存储从客户端发送过来的请求体数据
// 监听req的data事件
req.on('data', chunk => {
str += chunk;
})
// 监听req的end事件
req.on('end', () => {
const body = qs.parse(str);
req.body = body;
next();
})
}
module.exports = bodyParser;
2. 使用
const express = require('express');
const app = express();
const parser = require('./custom-body-parser');
app.use(parser)
app.post('/',(req,res)=>{
res.send(req.body);
})
app.listen(80, () => {
console.log('express server is running at http://127.0.0.1');
})
六、使用 Express 写接口
1. router.js
const express = require('express');
const router = express.Router();
router.get('/get', (req, res) => {
const query = req.query;
res.send({
status: 0,
message: 'GET 请求成功!',
data: query
})
})
router.post('/post',(req,res)=>{
const body = req.body;
res.send({
status:0,
message:'POST请求成功!',
data:body
})
})
module.exports = router;
2. 使用express写接口
const express = require('express');
const app = express();
app.use(express.urlencoded({extended:false}));
const router = require('./router');
app.use('/api', router);
app.listen(80, () => {
console.log('express server is running at http://127.0.0.1');
})
七、CORS
使用cors中间件解决跨域问题
步骤:
(1)运行 npm install cors 安装中间件
(2)使用 const cors = require('cors') 导入中间件
(3)在路由之前调用 app.use(cors()) 配置中间件
const express = require('express');
const app = express();
const cors = require('cors');
app.use(cors());
app.use(express.urlencoded({extended:false}));
const router = require('./router');
app.use('/api', router);
app.listen(80, () => {
console.log('express server is running at http://127.0.0.1');
})
注意问题:
a. cors主要在服务器端进行配置,客户端浏览器无须做任何额外的配置。
b. cors在浏览器中有兼容性,只有支持 XMLHttpRequest Level2 的浏览器,才能正常访问开启了cors的服务器端接口。
八、补充:项目中操作MySQL
1. 安装
npm init -y
npm i mysql
2. 配置
const mysql = require('mysql');
const db = mysql.createPool({
host: '127.0.0.1',
user: 'root',
password: 'admin123',
database: 'my_db_01'
})
// 测试mysql模块能否正常工作
db.query('select 1', (err, res) => {
if (err) {
return console.log(err.message);
}
console.log(res); //[ RowDataPacket { '1': 1 } ] 正确
})
3. 一些操作
3.1 查询 (查询结果为数组)
// 查询
const sqlStr = 'select * from users';
db.query(sqlStr, (err, res) => {
if (err) return console.log(err.message);
console.log(res);
})
3.2 插入
res为一个对象,通过affectedRows属性,判断是否成功插入数据
// 插入
const user = { username: '小红', password: '123' };
const sqlStr = 'insert into users (username,password) values(?,?)'; //使用问号表示占位
db.query(sqlStr, [user.username, user.password], (err, res) => {
if (err) return console.log(err.message);
if (res.affectedRows === 1) console.log('插入数据成功!');
})
注:插入数据的便捷方式
const user = { username: '小张', password: '123456' };
const sqlStr = 'insert into users set ?'; //
db.query(sqlStr, user, (err, res) => {
if (err) return console.log(err.message);
if (res.affectedRows === 1) console.log('插入数据成功!');
})
3.3 更新
res为一个对象,通过affectedRows属性,判断是否更新成功
// 更新
const user = { id: 7, username: '哈士奇', password: '123' };
const sqlStr = 'update users set username=?,password=? where id=?';
db.query(sqlStr,[user.username,user.password,user.id],(err,res)=>{
if(err) return console.log(err.message);
if(res.affectedRows === 1) {
console.log('更新数据成功!');
}
})
注:更新数据的便捷方式
const user = { id: 7, username: '萨摩耶', password: '123456' };
const sqlStr = 'update users set ? where id=?';
db.query(sqlStr,[user,user.id],(err,res)=>{
if(err) return console.log(err.message);
if(res.affectedRows === 1) {
console.log('更新数据成功!');
}
})
3.4 删除
// 删除
const sqlStr = 'delete from users where id=?';
db.query(sqlStr,5,(err,res)=>{
if(err) return console.log(err.message);
if(res.affectedRows === 1) {
console.log('删除数据成功!')
}
})
注意:标记删除(比如设计status这样的字段)
const sqlStr = 'update users set status=? where id=?';
db.query(sqlStr, [1, 7], (err, res) => {
if (err) return console.log(err.message);
if (res.affectedRows === 1)
console.log('标记删除成功!');
})
607

被折叠的 条评论
为什么被折叠?



