2023-02-27
Nodejs
00

目录

1. Express 初体验
1.1 认识Web框架
1.2 Express 安装
1.2.1 脚手架的方式搭建
1.2.3 从 0 搭建
2. Express 中间件
2.1 中间件是什么?
2.2 中间件可以执行哪些任务?
2.3 如何应用中间件
2.3.1. 注册最普通用的中间件
2.3.2 注册路径匹配的中间件
2.3.3 注册路径和请求方式中间件
2.3.4 注册多个中间件
2.4 内置 & 第三方中间件
2.4.1 body-parse
2.4.2 morgan
2.4.3 multer
2.5 其他
2.5.1 query & params
2.5.2 服务端的错误处理
2.5.3 静态资源服务器

1. Express 初体验

1.1 认识Web框架

上一章我们在使用 http 内置模块来搭建 Web 服务器的过程中,会感到很多问题,那就是原生 http 模块 在进行很多处理时会较为复杂,比如:

  1. URL 判断
  2. Method 判断
  3. 参数处理
  4. 逻辑代码处理等等

都需要我们自己来处理和封装,当所有的内容都放在一起时,常常会显得非常混乱。

而这些都是框架能帮我们解决的问题

目前在 Node 中比较流行的 Web 服务器框架是 expresskoaexpress 要早于 koa 出现,并且在 Node 社区中迅速流行起来。

  • 我们可以基于 express 快速、方便的开发自己的 Web 服务器
  • 并且可以通过一些实用工具和中间件来扩展自己功能

Express 整个框架的核心就是中间件,理解了中间件其他一切都非常简单!

1.2 Express 安装

express 的使用过程有两种方式:

  1. 通过 express 提供的脚手架 express-generator,直接创建一个应用的骨架

  2. 0 搭建自己的 express 应用结构

1.2.1 脚手架的方式搭建

  1. 安装脚手架
npm install express-generator -g
  1. 创建项目
express express-generator-demo
  1. 安装依赖
npm install
  1. 启动项目
npm run start
  1. 在浏览器输入 localhost:3000,访问成功,表示服务已启动

image.png

1.2.3 从 0 搭建

  1. 创建一个新的文件夹并安装 express
mkdir express-demo cd express-demo npm init npm i express
  1. 在这个文件夹下创建文件 01_express的基本使用.js
js
const express = require("express"); // 创建服务器 const app = express(); // home 的 get 请求处理 app.get("/home", (req, res) => { res.end("Hello Home"); }); // login 的 post 请求处理 app.post("/login", (req, res) => { res.end("Hello Login"); }); // 开启监听 app.listen(8000, () => { console.log("服务器启动成功~"); });
  1. 启动服务
node 01_express的基本使用.js
  1. 访问 http://localhost:8000/home 地址

image.png

2. Express 中间件

Express 是一个路由和中间件的 Web 框架,它本身的功能非常少,它的序本质上是一系列中间件函数的调用

2.1 中间件是什么?

中间件而定本质是传递给 express 的一个回调函数,这个回调函数接受三个参数:

  1. 请求对象 (request 对象)
  2. 响应对象 (response 对象)
  3. next 函数(在 express 中定义的用于执行下一个中间件的函数)

2.2 中间件可以执行哪些任务?

  1. 执行任何代码
  2. 更改请求和响应对象
  3. 结束请求-相应周期
  4. 调用栈中的下一个中间件

如果当前中间件功能没有 结束请求-相应周期,则必须调用 next() 将控制权传递给下一个中间件功能,否则,请求将被挂起。

image.png

2.3 如何应用中间件

  • express 主要提供两种方式:
    1. app/router.use;
    2. app/router.methods (methods 指的是常用的请求方式,比如 get post

2.3.1. 注册最普通用的中间件

express 接收到客户端发送的网络请求时,在所有中间件中开始进行匹配。

当匹配到第一个符合要求的中间件时,那么就会执行这个中间件

后续的中间件是否执行,取决于上一个中间件有没有执行 next

  1. 通过 use 方法注册的中间件是最普通/简单的中间件
  2. 通过 use 注册的中间件,无论是什么请求方式都可以匹配上
js
const express = require("express"); // 创建服务器 const app = express(); // app.use((req, res, next) => { console.log("我是最普通的中间件1"); next(); }); app.use((req, res, next) => { console.log("我是最普通的中间件2"); next(); }); // 开启监听 app.listen(8000, () => { console.log("服务器启动成功~"); });

启动服务,访问 localhost:8000 下面的两个中间件会依次执行 image.png

2.3.2 注册路径匹配的中间件

路径匹配的中间件不会对请求方式进行限制

js
const express = require("express"); // 创建服务器 const app = express(); // 注册路径匹配中间件 app.use('/home',(req,res,next) => { console.log('我是匹配到 /home 执行的中间件') }) // 开启监听 app.listen(8000, () => { console.log("服务器启动成功~"); });

启动服务,访问 http://localhost:8000/home,只有访问 '/home' 路径才会执行上面的中间件

2.3.3 注册路径和请求方式中间件

如果相对路径和请求方式都做限制可以使用 app.method(path, middleware) 的方式

js
const express = require("express"); // 创建服务器 const app = express(); app.get('/home',(req,res,next) => { console.log('我是匹配到 /home 的 get 请求时执行的中间件') }) // 开启监听 app.listen(8000, () => { console.log("服务器启动成功~"); });

只有当匹配到 /homeget 请求时才执行上面的中间件

2.3.4 注册多个中间件

当我们相对某个复杂的操作进行拆分的时候,就可以使用以下方式注册多个中间件

app.get(路径,中间件1,中间件2,中间件3)

js
const express = require("express"); // 创建服务器 const app = express(); app.get( "/home", (req, res, next) => { console.log("我是匹配到 /home 的 get 请求时执行的中间件1"); next() }, (req, res, next) => { console.log("我是匹配到 /home 的 get 请求时执行的中间件2"); next() }, (req, res, next) => { console.log("我是匹配到 /home 的 get 请求时执行的中间件3"); next() } ); // 开启监听 app.listen(8000, () => { console.log("服务器启动成功~"); });

2.4 内置 & 第三方中间件

并非所有的中间件都需要我们从零去编写:

  1. express 有内置一些帮助我们完成对 request 解析的中间件;
  2. registry 仓库中也有很多可以辅助我们开发的中间件;

2.4.1 body-parse

在客户端发送post请求时,会将数据放到body中:

  1. 客户端可以通过json的方式传递;
  2. 也可以通过form表单的方式传递

如果让我么你自己写中间件的话,通常需要做一些额外的逻辑判断

js
const express = require("express"); // 创建服务器 const app = express(); app.use((req,res,next) => { if(req.headers['content-type'] === 'application/json') { req.on('data', data => { const userInfo = JSON.parse(data.toString()) req.body = userInfo }) req.on('end', () => { next() }) } else { } }) // 开启监听 app.listen(8000, () => { console.log("服务器启动成功~"); });

但是,事实上我们可以使用 expres 内置的中间件或者使用 body-parser 来完成

js
app.use(express.json())

就像上面,我们只需要一行代码即可搞定,非常方便

如果解析的是 application/x-www-form-urlencoded,可以使用

app.use(express.urlencoded({extended: true}))

2.4.2 morgan

如果我们希望将请求日志记录下来,那么可以使用 express 官网开发的第三方库:morgan

因为是第三方库,所以需要先单独安装 morgan

npm i morgan
js
const fs = require("fs"); const express = require("express"); const morgan = require("morgan"); const loggerWriter = fs.createWriteStream("./log/access.log", { flags: "a+", }); // 创建服务器 const app = express(); app.use(morgan("combined", { stream: loggerWriter })); // 开启监听 app.listen(8000, () => { console.log("服务器启动成功~"); });

启动服务,接着在 ./log 目录下就会保存我们所有的请求日志了

image.png

2.4.3 multer

上传文件,我们可以使用 express 提供的 multer 来完成:

同样需要先安装 multer

npm i multer
js
const express = require("express"); const multer = require("multer"); const path = require("path"); // 创建服务器 const app = express(); const upload = multer({ storage: multer.diskStorage({ destination(req, file, cb) { cb(null, "uploads/"); }, filename: (req, file, cb) => { cb(null, Date.now() + "_" + path.extname(file.originalname)); }, }), }); // 单文件上传 app.post("/upload", upload.single("file"), (req, res, next) => { console.log(req.file); res.end("文件上传成功"); }); // 多文件上擦混 app.post("/photos", upload.array("photos"), (req, res, next) => { console.log(req.files); res.end("文件上传成功"); }); // 开启监听 app.listen(8000, () => { console.log("服务器启动成功~"); });

接着我们尝试通过 postman 上传一张图片

image.png

image.png

如果我们希望借助于 multer 帮助我们解析一些 form-data 中的普通数据,那么我们可以使用 any

image.png

js
app.use(upload.any()) app.use('login', (req,res,next) => { console.log(req.body) })

2.5 其他

2.5.1 query & params

客户端传递到服务器参数的方法常见的是 5 种:

  1. 方式一:通过 get 请求中的 URLparams
  2. 方式二:通过 get 请求中的 URLquery
  3. 方式三:通过 post请求中的 bodyjson 格式(中间件中已经使用过);
  4. 方式四:通过 post 请求中的 bodyx-www-form-urlencoded 格式(中间件使用过);
  5. 方式五:通过 post 请求中的 form-data 格式(中间件中使用过);

关于传递参数 paramsquery 的使用也是非常简单的

请求地址:http://localhost:8000/login/abc/zhangsan

  • 获取参数
js
app.use('/login/:id/:name',(req,res,next) => { console.log(req.params) res.json('请求成功') })

请求地址:http://localhost:8000/login?username=zhangsan&password=123456

  • 获取参数
js
app.use('/login',(req,res,next) => { console.log(req.qeury) res.json('请求成功') })

2.5.2 服务端的错误处理

js
app.use((err, req, res, next) => { const message = err.message; switch (message) { case "USER DOES NOT EXISTS": res.status(400).json({ message }); } res.status(500); });

2.5.3 静态资源服务器

部署静态资源我们可以选择很多方式:

  • Node 也可以作为静态资源服务器,并且 express 给我们提供了方便部署静态资源的方法;
js
const express = require("express"); const app = express() app.use(express.static('./build')) app.listen(8000, ()) => { console.log('静态服务器启动成功') })
如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:叶继伟

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!