node中间件-express框架

news2024/11/25 11:37:22

文章目录

    • 前置 Express安装
    • 1. 基本使用
    • 2. 中间件
      • 2.1 中间件应用
    • 3. 中间件的注册方式
      • 3.1 普通中间件的注册
      • 3.2 path匹配中间件
      • 3.3 method与路径匹配
      • 3.4 案列中间件匹配与执行方法
    • 4. 中间件request数据解析
      • 4.1 解析request body中间件
      • 4.2 urlencoded解析
    • 5. 第三方中间件
      • 5.1 morgan 日志记录
      • 5.2 multer 文件上传
    • 6. 参数解析 params和query
    • 7. 响应数据
    • 8. 路由
    • 9. 静态资源
    • 10 错误处理

前置 Express安装

  • 方式一 : express提供的脚手架,直接创建一个应用的骨架
  1. 安装脚手架npm install -g express-generator
  2. 创建项目 express express-demo
  3. 安装依赖npm install
  4. 启动项目 node bin/www
  • 方式二 : 从零搭建自己的express应用结构;
  1. 初始化项目 npm init
  2. 安装express npm i express

1. 基本使用

  1. 导入–>创建–>监听
  2. 使用参考文档

const express = require('express');
//  * 创建express服务器
const app=express()
//  * 启动服务器 ,监听端口

app.listen(8000,()=>{
	console.log('启动express 服务器')
})

// 请求
app.post('/login',(req,res)=>{
     res.end('登录成功')
})

app.get('/home',(req,res)=>{
    res.end('home 列表模块')
})

2. 中间件

  • 中间件的本质是传递给express的一个回调函数;
  • 这个回调函数接受三个参数:
    • 请求对象(request对象);
    • 响应对象(response对象);
    • next函数(在express中定义的用于执行下一个中间件的函数);
      重要 :中间件的执行过程,只会执行第一次匹配的中间件,关于后面是否执行看next
app.post('/login', (req, res, next) => {
    // 中间件中的req与res可以进行修改
    res.aaa = '添加aaa并修改res'
    // 2. JSON结束
    // res.json({message:'登录成功',code:200})
    // res.end('登录成功')
    // 3. next 匹配执行下一个中间件
    next()
})
  • 注意点如果当前中间件功能没有结束请求-响应周期,则必须调用next()这将控制权传递给下一个中间件功能,否则,请求将被挂起
    在这里插入图片描述

const express = require('express');
//  * 创建express服务器
const app = express()
//  * 启动服务器 ,监听端口

app.listen(8000, () => {
    console.log('启动express 服务器')
})

// 请求
app.post('/login', (req, res, next) => {
    // 中间件中的req与res可以进行修改
    res.aaa = '添加aaa并修改res'
    // 2. JSON结束
    // res.json({message:'登录成功',code:200})
    // res.end('登录成功')
    // 3. next 匹配执行下一个中间件
    next()
})

app.use((req,res,next)=>{
    console.log('执行下一个中间件next');
})

app.get('/home', (req, res) => {
    res.end('home 列表模块')
})

2.1 中间件应用

  • express主要提供了两种方式:
    • app/router.use;
    • app/router.methods;

app.use

app.use((req,res,next)=>{
    console.log('执行下一个中间件next');
})

app.methods


app.get('/home', (req, res) => {
    res.end('home 列表模块')
})

3. 中间件的注册方式

3.1 普通中间件的注册

  • use注册的中间件不管什么路径或者请求都可以匹配的上
  • 同时在匹配的过程中如何不 next(), 只会执行第一个中间件
// 1. use注册的中间件不管什么路径或者请求都可以匹配的上
// 2. 同时在匹配的过程中如何不 next(), 只会执行第一个中间件
app.use((req,res,next)=>{
    console.log('执行下一个中间件next');
    next()
})

app.use(()=>{
    console.log('执行第二个中间件')
})

3.2 path匹配中间件

-路径匹配中间件只是对路径做限制并没有对请求方式做显示

// 这里的路径匹配中间件只是对路径做限制并没有请求方式做显示
// 不管method如何都可以匹配 
app.use('/home',(req,res,next)=>{
	console.log('路径匹配中间件')
})

3.3 method与路径匹配

  • 语法: app.method(path,middleware)
  • 匹配中间件只会匹配第一个符合要求的中间件 , 关于下一个中间件是否执行看有没有调用next
// app.method(path,middleware)
app.get('/home',(req,res,next)=>{
	console.log('路径以及方法匹配');
	res.end('匹配成功')
})

// 注册多个中间件
app.get('/home', (req, res, next) => {
	console.log('路径以及方法匹配');
	res.end('匹配成功')
	// 中间的匹配只会匹配第一个符合要求的中间件 , 关于下一个中间件是否执行看有没有调用next
}, (req, res, next)=>{
   console.log('关于这个中间件的执行需要看上一个中间件是否有next');
})

3.4 案列中间件匹配与执行方法

  • 普通直接写法
app.post('/login', (req, res, next) => {
	req.on('data', data => {
		let userInfo = data.toString()
		const user = JSON.parse(userInfo)
		if (user.username === 'admin' && user.password===123456) {
			res.end('登录成功')
		}else{
			res.end('账号或者密码错误')
		}
	})

})

//  注册信息
app.post('/register', (req, res, next) => {
	// res.end('注册成功')
	// 注册要查询数据库,看是否存在用户名
   if (true) {
		 req.on('data', data => {
			 let userInfo = data.toString()
			 const user = JSON.parse(userInfo)
			 if (user.username === 'admin' && user.password === 123456) {
				 res.end('注册成功')
			 } else {
				 res.end('账号或者密码错误')
			 }
		 })
	 }

})
  • ** 优化 JSON解析,放到body后next()**
// 1. JSON解析,放到body
app.use((req, res, next) => {
	if (req.headers['content-type'] === 'application/json') {
		req.on('data', data => {
			const jsonInfo = JSON.parse(data.toString())
			req.body = jsonInfo
		})
		req.on('end', () => {
			next()
		})
	}
})

// 账号密码
app.post('/login', (req, res, next) => {
  console.log(req.body);
	res.end('登录成功')
})
//  注册信息
app.post('/register', (req, res, next) => {
	console.log(req.body);
})

4. 中间件request数据解析

  • express有内置一些帮助我们完成对request解析的中间件;

4.1 解析request body中间件

app.use((req, res, next) => {
	if (req.headers['content-type'] === 'application/json') {
		req.on('data', data => {
			const jsonInfo = JSON.parse(data.toString())
			req.body = jsonInfo
		})
		req.on('end', () => {
			next()
		})
	}
	next()
})
// 账号密码
app.post('/login', (req, res, next) => {
  console.log(req.body);
	res.end('登录成功')
})
  • 上面代码中利用JSON.parse对data数据进行解析 ,但是 express中提供了 json可以直接进行解析
app.use(express.json())
// 账号密码
app.post('/login', (req, res, next) => {
  console.log(req.body);
	res.end('登录成功')
})

4.2 urlencoded解析

  • 解析客户端利用urlencoded传参 , 这时就需要用 express.urlencoded()
    在这里插入图片描述
app.use(express.urlencoded())  // 解析客户端利用urlencoded传参
// 解决 body - parser deprecated undefined extended: provide extended option 05urlencoded警告
app.use(express.urlencoded({ extended: true }))
app.post('/login', (req, res, next) => {
	console.log(req.body);
	res.end('登录成功')
})

5. 第三方中间件

5.1 morgan 日志记录

const express = require('express');
const morgan = require('morgan');
const fs = require('fs');
const app = express()
// cnpm i morgan  安装
// 第三方中间件 合并日志
const writerLog=fs.createWriteStream('./log.txt')
// 日志写入
app.use(morgan('combined', { stream: writerLog }))
app.post('/login', (req, res, next) => {
	console.log(req.body);
	res.end('登录成功')
})

5.2 multer 文件上传

  1. 安装 npm i multer --save
  2. Multer 只处理任何 multipart/form-data 类型的表单数据。
  3. Multer 会在express 的 request 对象里添加一个 body 对象 (包含表单的文本域信息)以及 filefiles 对象 (单文件通过req.file获取,多文件通过req.files获取,file 或 files 对象包含对象表单上传的文件信息)。
  4. 注意点 upload.single的值,对应前端name中的值,同时也要保住 form-data 中key的值相同。
const multer = require('multer');
// 对上传的文件名字重起
const upload = multer({
	storage: multer.diskStorage({
		//  文件名称, 
		// destination 是用来确定上传的文件应该存储在哪个文件夹中
		// destination 是一个函数,必须创建这个文件夹
		destination(require, file, callback) {
			callback(null, 'uploads/')
		},
		filename(require, file, callback) {
			// originalname是文件上传时的名字,可以根据它获取后缀
			callback(null, Date.now() + '_' + file.originalname)
		}
	})
})
app.post('/upload', upload.single("file"), (req, res, next) => {
	console.log(req.file);  // 文件信息
	res.end('文件上传成功')
})

  • 多文件上传 ,接受的是一个数组
  • 同时在 multer实例.array(fielname[,maxCount])——接收一个以fielname命名的文件数组;maxCount——限制上传的最大数量,这些文件的信息保存在req.files里面
app.post('/upload', upload.array("file"), (req, res, next) => {
	console.log(req.files);  // 文件信息
	res.end('文件上传成功')
})

参考解析

  • storage存储引擎以及错误处理
  • 前后端上传案例

解析form-data中的普通数据

const formData=  multer()
app.post('/login',formData.any(), (req, res, next) => {
	console.log(req.body);  
	res.end('登录成功')
})

6. 参数解析 params和query

  • query 主要用于分页
app.post('/list', (req, res, next) => {
	// http://localhost:8000/list?offset=10&page=20解析
	console.log(req.query);   // { offset: '10', page: '20' }
	res.end('登录成功')
})
  • params 主要用于id的传递
app.post('/user/:id', (req, res, next) => {
	// http://localhost:8000/user/1100
	
	const id = req.params.id
	res.end(`获取用户${id}`)
})

7. 响应数据

  • end方式 : 类似于http中的response.end方法,用法是一致的
  • json方法 : json方法中可以传入很多的类型:object、array、string、boolean、number、null等,它们会被转换成json格式返回
  • status方法 : 用于设置状态码;注意 是函数
  • 其他响应内容参考

app.get('/login', (req, res, next) => {
	// 1. 方法一 end
	// res.end(`响应数据---登录成功`)
	//  2. JSON数据响应
	// res.json({
	// 	code: 0, message: '欢迎回来', data: [{
	// 		name: "admin",
	// 		avator:'www.http.ccc.jpg'
	// 	}]
	// })

	//  3. status 方法,设置http状态码
	res.status(201)
	res.json(
		{
			code: 0, message: '欢迎回来', data: [{
				name: "admin",
				avator: 'www.http.ccc.jpg'
			}]
		}
	)
})

8. 路由

  • express.Router来创建一个路由处理程序

useRouter.js

const express = require('express');
const userRouter = express.Router()
userRouter.get('/', (req, res, next) => {
	res.json(
		{
			code: 0, message: 'success', data: [{
				name: "admin",
				password:'123456'
			}, {
					name: "admin",
					password: '123456'
				}]
		}
	)
})
userRouter.get('/:id',(req, res, next) => {
	const id=req.params.id
	res.end(id)
})
userRouter.post('/', (req, res, next) => {
})
userRouter.delete('/:id', (req, res, next) => {
})
userRouter.patch('/:id', (req, res, next) => {

})

module.exports=userRouter

index.js

const userRouter = require('./router/userRouters.js');
app.use('/users', userRouter)

参考文章 :路由在项目中的具体使用

9. 静态资源

  1. express 内置static() 静态资源,直接将文件夹做一个静态资源
app.use(express.static('./uploads')) 

10 错误处理

  • 普通的错误处理,需要利用前端的数据进行if判断处理
  • 但是每一个接口写一个判断或者返回的错误信息以及状态码相同,这就会造成代码的甬余
app.post('/login', (req, res, next) => {
	const { username, password } = req.body
	if (username !== 'admin' || password !== 123456) {

		res.json({
			code: 1002,
			message: '账号密码错误'
		})
	} else {
		console.log('xx')
		res.json({
			code: 200,
			message: '登录成功'
		})
	}
})
  • 简单封装统一处理
// 中间件处理错误信息
app.post('/login', (req, res, next) => {
	if (username !== 'admin' || password !== 123456) {
		next(1002)
	}
	else {
		next()
	}
})
app.use((errCode, req, res, next) => {
	const code = errCode
	let message = ''
	switch (code) {
		case 1001:
			message = '未知的错误'
			break
		case 1002:
			message = '账号或密码错误'
		default:
			message = '登录成功'
	}
	res.json({
		code: errCode,
		message,
	})
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/782648.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CHI协议保序之Comp保序

一致性系统中,需要 memroy model 使用 multi-copy atomicity; 一致性系统中,使用三种保序方式; Completion response □ Comp 响应 表示当前的请求,己经达到了 POC/POS, POC/POS 将保证其命令的执行顺序和接收的顺序是一致的&…

Python(三十三)分支结构——嵌套if的使用

❤️ 专栏简介:本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中,我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 :本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…

Android Studio下载

目录 确定版本下载地址 确定版本 如果是入职工作,先和同事确定好版本。因为每个项目使用的gradle插件版本,是在根目录的build.gralde文件中统一定义的,这个文件在添加第三方库(例如GreenDao,Arouter等)或者…

SpringBoot项目的创建

等待maven下载完成 删除无用文件 此时我们就创建成功了

Shiro权限绕过漏洞(CVE-2020-1957,CVE-2020-11989、CVE-2020-13933)

一、Apache Shiro Apache Shiro 是一个强大且易用的Java安全框架,能够用于身份验证、授权、加密和会话管理。 二、Shiro漏洞指纹(部分) 1、在请求包的cookie中有remember字段赋任意值 2、返回包中存在set-Cookie:remeberMedeleteMe 三、受…

通过宝塔面板将vue项目放到阿里云服务器(两个vue项目)

前提条件: 端口提前开放所需环境安装好(Nginx node…)以及打包好的vue文件(dist) 第一步:上传文件到自定义目录 第二步:在首页找到Nginx软件并配置 第三步:配置具体的配置 这里说…

「雕爷学编程」Arduino动手做(39)——DS18B20温度传感器3

37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&#x…

厦门枫叶时代看电视的新趋势

随着“5G电视”技术的不断普及和城市数字化转型的加速,电视行业也在发生着翻天覆地的变化。在这个背景下,第28届上海电视节推出了高端论坛板块——“白玉兰对话”,共同探讨电视行业的未来发展。其中备受瞩目的中国电视剧发展论坛,…

荔枝派Zero(全志V3S)驱动开发之USB摄像头

文章目录 前言一、内核配置 UVC二、编译内核并烧录到 SD 卡三、上电测试四、mjpeg-streamer 视频流服务器测试1、jpeg 库的移植2、移植 mjpeg-streamer①、前置软件②、下载 mjpg-streamer 源码③、修改 mjpg-streamer 源码④、编译 mjpg-streamer 源码 3、搬移文件到 nfs 目录…

2023/07/23

1. 必须等待所有请求结束后才能执行后续操作的处理方式 方式一: async func () {const p1 await api1();const p2 await api2();const p3 await api3();Promise.all([p1, p2, p3]).then(res > {后续操作...}) }方式二:待补充 2. flex 弹性盒子布…

300M的联通宽带,电脑直接连接光猫只有100M;电脑连接路由器,然后路由器连接光猫却有300M???

1. 现象 300M的联通宽带,用了小半年之后发现网络比以前满,通过https://www.speedtest.cn网站测试发现只有100M 2. 猜测 难道是联通这帮人,偷偷把我网速降到了100M??? 3. 排查过程 打电话让联通师傅上门排查…

使用 Qt designer

使用 Qt designer 1、配置Qt designer外部工具2、Qt designer(Qt 设计师)使用2.1 创建保存文件ui2.2 pyuic5.exe 工具 转化成为py文件2.3 直接导入UI文件 2、qrc资源管理器 1、配置Qt designer外部工具 实质就是 Qt\bin 工具中 designer.exe 请查看 PyQ…

Docker 核心概念深度解析:探索容器、镜像和仓库在Docker生态系统中的重要作用和 应用

🌷🍁 博主 libin9iOak带您 Go to New World.✨🍁 🦄 个人主页——libin9iOak的博客🎐 🐳 《面试题大全》 文章图文并茂🦕生动形象🦖简单易学!欢迎大家来踩踩~&#x1f33…

Redis应用(3)——Redis的项目应用(二):抢购图书 ---> Redis高并发的问题 分布式锁Redission的使用

目录 引出Redis的高并发问题redis的高并发问题Redisson中间件引入RedissonRedisson配置Redisson应用报错:java.lang.NoClassDefFoundErro Redis的项目应用(二):抢购图书1.0版本,Java代码:数据不安全测试方法…

Python+Selenium做自动化测试

一.项目介绍 目的 测试某官方网站登录功能模块可以正常使用 用例 1.输入格式正确的用户名和正确的密码,验证是否登录成功; 2.输入格式正确的用户名和不正确的密码,验证是否登录失败,并且提示信息正确; 3.输入格式正…

H 欢乐颂+J 睡美人

H 欢乐颂 登录—专业IT笔试面试备考平台_牛客网 思路:这个题就是题意比较难懂,思路还挺好想的,其实就是每个点都有几个状态,然后只有存在相同状态的点之间才可以连边,假设点i的状态和为a,点j的状态和为b&a…

Packet Tracer – 配置无线路由器上的端口转发

Packet Tracer – 配置无线路由器上的端口转发 地址分配表 设备 接口 IP 地址 子网掩码 LA 互联网 209.165.134.1 255.255.255.252 LAN 192.168.0.1 255.255.255.0 拓扑图 目标 第 1 部分:配置端口转发 第 2 部分:验证 ServerA 远程连接 …

C语言基础:预处理指令的使用

本文结合工作经验,研究C语言中常见的预处理指令的用法。 文章目录 1 预处理指令概念2 常见的预处理指令2.1 #include包含头文件2.2 #define定义宏2.2.1 类对象宏(object-like macro)2.2.2 类函数宏(function-like macro&#xff…

Docker 镜像的创建

Docker 镜像的创建 创建镜像有三种方法,分别为基于已有镜像创建、基于本地模板创建以及基于Dockerfile创建。 1.基于现有镜像创建 基于现有镜像创建 先使用现有镜像创建容器 docker run 再进入容器进行内容的更新 docker exex 最后提交成新的进行 …

C++语法总结

今天给大家带来的不是某个知识点的解说,而是我花了几个小时的时间,写的一个C的思维导图,希望大家能够喜欢 以上是我对C语法的一些理解,有些可能是我遗漏了,有不对的地方希望大家能够指出,最后,子…