Express

目录

一、简介

二、基本使用

1. 安装

2. 创建基本的Web服务器

2.1 创建web服务器

2.2 监听GET与POST请求

2.3 获取URL中携带的查询参数

2.4 托管静态资源

2.5 小工具 nodemon

三、Express 路由 

1. 最简单的用法

2. 模块化路由

四、Express 中间件

1. 全局生效的中间件

2. 定义全局中间件的简化形式

3. 中间件的作用

4. 定义多个全局中间件

5. 局部生效的中间件

6. 注意事项

7. 中间件的分类 

五、应用-自定义解析表单数据的中间件

六、使用 Express 写接口

七、CORS

使用cors中间件解决跨域问题

八、补充:项目中操作MySQL

1. 安装

2. 配置

3. 一些操作

3.1 查询 (查询结果为数组)

3.2 插入

3.3 更新

3.4 删除


一、简介

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('标记删除成功!');
})

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值