基于NodeJs+Express+MySQL 实现实现登录注册接口+token生成与解析验证+跨域-CORS

这篇具有很好参考价值的文章主要介绍了基于NodeJs+Express+MySQL 实现实现登录注册接口+token生成与解析验证+跨域-CORS。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、express是什么?

二、安装 express

三、安装Mysql

四、安装 nodemon 实现项目热更新

五、这里先了解下express的post get delete接口

post接口说明:

get接口说明 :

 DELETE 接口

六、注册功能

1、流程分析

校验表单数据是否合法

检测用户名是否占用

密码加密处理

插入新用户

2、完整注册接口

regUser(req, res) 注册函数

七、封装错误处理函数(即:注册功能使用的res.cc)

八、登录功能

1、流程分析

1.判断前端提交的后端的数据是否合法。

2.查询登录的用户是否存在。

3.判断当前用户的密码是否正确。

2、生成token字符

 1.安装jsonwebtoken用于生成token

2.导入jsonwebtoken

 3.全局配置文件(里面有token的密钥)

3.使用jwt.sign对用户的信息进行加密,生成 token 字符串 

4.登录成功后将生成的token返回给客户端

3、登录接口的完整代码

1.login()登录函数代码

九、最后附上users路由模块和登录注册函数.js的完整代码

users.js

login.js登录注册函数

接口文档:

十、解析token中间件

 1.安装解析中间件

2.在App.js 中引入

3.注册全局中间件并解析token

4.注册全局错误中间件 当token失效时 返回信息

十一、CORS跨域中间件

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

完整代码:(jsonp就不做过多解释了)

1、CORS 响应头部 - Access-Control-Allow-Origin

2、CORS 响应头部 - Access-Control-Allow-Headers

3、CORS 响应头部 - Access-Control-Allow-Methods

4、 CORS请求的分类

5、 简单请求

6、预检请求


一、express是什么?

  1. Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具。
  2. 使用 Express 可以快速地搭建一个完整功能的网站。
  3. Express 框架核心特性:
  • 可以设置中间件来响应 HTTP 请求。

  • 定义了路由表用于执行不同的 HTTP 请求动作。

  • 可以通过向模板传递参数来动态渲染 HTML 页面。

二、安装 express

搭建Express项目有两种方式:

  • 方式一:从零搭建自己的express应用结构
  • 方式二:安装express-generator脚手架 一键生成express项目

在这里我们使用方式二快速构建一个express项目:

        express-generator 是 Express 应用程序生成器工具,我们可以使用它来快速创建应用程序框架。

  1. 在项目文件夹下打开node终端
  2. 安装express-generator 脚手架

    npm install -g express-generator
  3. 创建项目
    express expressFrame (expressFrame 是项目名)

         执行完后项目目录下的结构

nodejs 实现登录,Express,nodejs,express,node.js

 注:bin/www 是启动入口文件,在里面可以设置端口号等

3. 安装依赖

npm install

4. 启动项目
 

npm start

nodejs 实现登录,Express,nodejs,express,node.js

此时在浏览器打开 http://localhost:3000/

nodejs 实现登录,Express,nodejs,express,node.js

 出现以上页面,那么恭喜你express服务器已创建完成

三、安装Mysql

npm i mysql

1、新建db 数据库文件夹,文件夹下新建index.js 用来配置数据库信息,index.js内容如下

// 导入 mysql 模块
const mysql = require('mysql')
// 建立与 MySQL 数据库的连接
const db = mysql.createPool({
	host: '127.0.0.1', // 数据库的IP地址
	port: 3306, //数据库端口号
	user: 'web2245321733', // 登录数据库的账号
	password: 'web2245321733', // 登录数据库的密码
	database: 'web2245321733' // 指定要操作哪个数据库
})

// 检测数据库是否连接成功
db.query("select 1", (err, results) => {
	if (err) return console.log(err);
	console.log(results, '数据库链接成功');
});

module.exports = db

此时重启项目,终端看到打印出数据库链接成功,nodejs 实现登录,Express,nodejs,express,node.js

四、安装 nodemon 实现项目热更新

在刚才的添加数据库当中,我们发现每次修改代码都需要重启项目,非常麻烦

1、安装 nodemon 来监控 node.js 源代码的任何变化和自动重启你的服务器

npm install -g nodemon

2、在package.json中修改启动命令

nodejs 实现登录,Express,nodejs,express,node.js

 然后重启项目,就可以了。

五、这里先了解下express的post get delete接口

post接口说明:

// 定义 POST 接口
router.post('/post', (req, res) => {
  // 通过 req.body 获取请求体中包含的 url-encoded 格式的数据
  const body = req.body
  // 调用 res.send() 方法,向客户端响应结果
  res.send({
    status: 0, // 0 表示处理成功,1 表示处理失败
    msg: 'POST 请求成功!', // 状态的描述
    data: body, // 需要响应给客户端的数据
  })
})

get接口说明 :

// 在这里挂载对应的路由
router.get('/get', (req, res) => {
  // 通过 req.query 获取客户端通过查询字符串,发送到服务器的数据
  const query = req.query
  // 调用 res.send() 方法,向客户端响应处理的结果
  res.send({
    status: 0, // 0 表示处理成功,1 表示处理失败
    msg: 'GET 请求成功!', // 状态的描述
    data: query, // 需要响应给客户端的数据
  })
})

 DELETE 接口

// 定义 DELETE 接口
router.delete('/delete', (req, res) => {
  res.send({
    status: 0,
    msg: 'DELETE请求成功',
  })
})

参数说明:

  • router.post 用于创建post接口  它有两个参数 参数1:路由匹配规则    参数2:请求的回调函数
  • 回调函数的req参数:客户端请求信息,包括 请求头 请求参数等,req.bodey或req.query获取请求参数
  • 回调函数的res参数:用于提交服务端的响应给客户端
  • 调用 res.send() 方法,向客户端响应处理的结果

六、注册功能

1、流程分析

注册的一般流程 1.校验表单数据是否合法 2.检测用户名是否占用 3.密码加密处理 4.插入新用户

校验表单数据是否合法

// 通过 req.body 获取请求体中包含的 url-encoded 格式的数据
	const userInfo = req.body
	//【步骤一】对客户端的数据进行校验
	if (userInfo.username == '' || userInfo.password == '') {
		return res.send({
			status: 1,
			msg: '用户名和密码不能为空'
		})
	}

检测用户名是否占用

// 定义sql语句,查询用户名是否被占用
	let sql = 'select * from ev_users where username=?'
	db.query(sql, [userInfo.username], (error, result) => {
		if (error) {
			return res.cc(error)
		}
		if (result.length > 0) {
			return res.cc('用户名已被占用!')
		}
	})

密码加密处理

安装bcryptjs 加密包 用于密码加密

npm i bcryptjs

 引入加密包

// 导入 bcryptjs 加密包
const bcrypt = require('bcryptjs')

调用 bcrypt.hashSync() 对密码加密

// 调用 bcrypt.hashSync() 对密码加密
		userInfo.password = bcrypt.hashSync(userInfo.password, 10)

 说明:bcrypt.hashSync() 的参数1:要加密的密码  参数2: 加密等级 填10即可

插入新用户

前面我们已经连接过数据库了,这里我们直接引入数据库操作模块

// 导入数据库操作模块
const db = require('../../db/index')

 定义插入新用户的 SQL 语句

// 定义插入新用户的 SQL 语句
		let sql1 = 'insert into ev_users set ?'

 调用 db.query() 执行 sql 语句 插入新用户 并给客户端返回结果

// 调用 db.query() 执行 sql 语句
		db.query(sql1, {
			username: userInfo.username,
			password: userInfo.password
		}, (error, result) => {
			if (error) return res.cc(error)
			// 判断影响行数是否为 1
			if (result.affectedRows !== 1) return res.cc('注册用户失败!')
			return res.cc('注册用户成功', 0, {
				username: userInfo.username
			})
		})

2、完整注册接口

  • 打开routes文件夹下的users.js 路由模块,添加以下内容
/**
 * POST 用户注册
 * @param username  用户名
 * @param password  用户密码
 */
router.post('/add', (req, res, next) => {
	// 通过 req.body 获取请求体中包含的 url-encoded 格式的数据
	console.log(req.body)
	const userInfo = req.body
	//【步骤一】对客户端的数据进行校验
	if (userInfo.username == '' || userInfo.password == '') {
		return res.send({
			status: 1,
			msg: '用户名和密码不能为空'
		})
	}
	// 【步骤二】执行定义好的注册函数
	regUser(req, res)
});

regUser(req, res) 注册函数

在这里我单独新建了个login.js文件用于写注册和登录的处理的函数放

nodejs 实现登录,Express,nodejs,express,node.js

 引入

// 导入写好的注册/登录函数
const {
	regUser,
	login
} = require('../public/javascripts/login')

regUser(req, res) 注册函数内容如下:

// 导入数据库操作模块
const db = require('../../db/index')
// 导入 bcryptjs 加密包
const bcrypt = require('bcryptjs')

/**
 * POST 用户注册
 * @param username  用户名
 * @param password  用户密码
 */
exports.regUser = (req, res) => {
	// 获取客户端提交到服务器的用户信息
	const userInfo = req.body
	// 定义sql语句,查询用户名是否被占用
	let sql = 'select * from ev_users where username=?'
	db.query(sql, [userInfo.username], (error, result) => {
		if (error) {
			return res.cc(error)
		}
		if (result.length > 0) {
			return res.cc('用户名已被占用!')
		}
		// 调用 bcrypt.hashSync() 对密码加密
		userInfo.password = bcrypt.hashSync(userInfo.password, 10)
		// 定义插入新用户的 SQL 语句
		let sql1 = 'insert into ev_users set ?'
		// 调用 db.query() 执行 sql 语句
		db.query(sql1, {
			username: userInfo.username,
			password: userInfo.password
		}, (error, result) => {
			if (error) return res.cc(error)
			// 判断影响行数是否为 1
			if (result.affectedRows !== 1) return res.cc('注册用户失败!')
			return res.cc('注册用户成功', 0, {
				username: userInfo.username
			})
		})
	})
}

/**
 * POST 登录的回调函数
 * @param username  用户名
 * @param password  用户密码
 */
exports.login = (req, res) => {
	
}

七、封装错误处理函数(即:注册功能使用的res.cc)

在注册功能里我对res.send向客户端响应函数做了处理,

在app.js中,放在路由前面

//封装错误处理函数
app.use((req, res, next) => {
	res.cc = function(err, status = 1, data = {}) {
		res.send({
			status,
			data,
			message: err instanceof Error ? err.message : err
		})
	}
	next()
})

八、登录功能

1、流程分析

登录的一般流程 1.判断前端提交的后端的数据是否合法。 2.查询登录的用户是否存在。 3.判断当前用户的密码是否正确。

1.判断前端提交的后端的数据是否合法。

// 通过 req.body 获取请求体中包含的 url-encoded 格式的数据
	console.log(req.body)
	const userInfo = req.body
	//【步骤一】对客户端的数据进行校验
	if (userInfo.username == '' || userInfo.password == '') {
		return res.send({
			status: 1,
			msg: '用户名和密码不能为空'
		})
	}

2.查询登录的用户是否存在。

// 定义 SQL 语句
	const sql = 'select * from ev_users where username=?'
	// 执行 SQL 语句,根据用户名查询用户的信息
	db.query(sql, userInfo.username, (err, result) => {
		// 执行 SQL 语句失败
		if (err) return res.cc(err)
		// 执行 SQL 语句成功,但是获取的数据条数不为1 也是失败的
		if (result.length !== 1) return res.cc('登录失败!')
		// 经过上方俩条判断条件,则证明执行 SQL 成功
	})

3.判断当前用户的密码是否正确。

使用 加密包的bcrypt.compareSync方法对比用户提交的密码和数据库中的密码是否一致,如果一直即:登录成功

// TODO :判断密码是否正确
		const comRes = bcrypt.compareSync(userInfo.password, result[0].password)
		if (!comRes) return res.cc('登陆失败')

2、生成token字符

密码正确的话,登录成功,根据用户信息生成唯一的token返回给客户端

 1.安装jsonwebtoken用于生成token

npm i jsonwebtoken

2.导入jsonwebtoken

// 导入生成Token的包
const jwt = require('jsonwebtoken')

 3.全局配置文件(里面有token的密钥)

config.js放在根目录

// 全局配置文件 config.js
module.exports = {
	// 加密和解密 token 的密钥
	jwtSecretKey: 'itheima No1. ^_^',
	// token 有效期
	expiresIn: '10h'
}

导入

// 导入全局配置文件(里面有token的密钥)
const config = require('../../config')

3.使用jwt.sign对用户的信息进行加密,生成 token 字符串 

jwt.sign 有三个参数依次是 生成token的数据,加密的形式,token有效期

 加密前先处理用户信息,将用户的敏感信息置空(如:密码等)

// 在服务器端生成 Token 字符串
		const user = {
			...result[0], // 解构用户信息
			password: '', //密码等敏感信息置空
		}
		// 对用户的信息进行加密,生成 token 字符串 
		const tokenStr = jwt.sign(user, config.jwtSecretKey, {
			expiresIn: config.expiresIn //tonken 有效期
		})

4.登录成功后将生成的token返回给客户端

// 调用 res.send 将Token响应给客户端
		res.send({
			status: 0,
			data: {
				user: user,
				token: 'Bearer ' + tokenStr,
			},
			message: '登录成功!!!',
		})

3、登录接口的完整代码

/**
 * POST 用户登录
 * @param username  用户名
 * @param password  用户密码
 */
router.post('/login', (req, res, next) => {
	// 通过 req.body 获取请求体中包含的 url-encoded 格式的数据
	// console.log(req.body)
	const userInfo = req.body
	//对客户端的数据进行校验
	if (userInfo.username == '' || userInfo.password == '') {
		return res.send({
			status: 1,
			msg: '用户名和密码不能为空'
		})
	}
	// 执行定义好的登录函数
	login(req, res)
});

1.login()登录函数代码

/**
 * POST 登录的回调函数
 * @param username  用户名
 * @param password  用户密码
 */
exports.login = (req, res) => {
	console.log('user', req.user);
	// 接收表单的数据
	const userInfo = req.body
	// 定义 SQL 语句
	const sql = 'select * from ev_users where username=?'
	// 执行 SQL 语句,根据用户名查询用户的信息
	db.query(sql, userInfo.username, (err, result) => {
		// 执行 SQL 语句失败
		if (err) return res.cc(err)
		// 执行 SQL 语句成功,但是获取的数据条数不为1 也是失败的
		if (result.length !== 1) return res.cc('登录失败!')
		// 经过上方俩条判断条件,则证明执行 SQL 成功

		// TODO :判断密码是否正确
		const comRes = bcrypt.compareSync(userInfo.password, result[0].password)
		if (!comRes) return res.cc('登陆失败')
		// 在服务器端生成 Token 字符串
		const user = {
			...result[0], // 解构用户信息
			password: '', //密码等敏感信息置空
		}
		// 对用户的信息进行加密,生成 token 字符串 
		const tokenStr = jwt.sign(user, config.jwtSecretKey, {
			expiresIn: config.expiresIn //tonken 有效期
		})
		// 调用 res.send 将Token响应给客户端
		res.send({
			status: 0,
			data: {
				user: user,
				token: 'Bearer ' + tokenStr,
			},
			message: '登录成功!!!',
		})
	})
}

九、最后附上users路由模块和登录注册函数.js的完整代码

users.js

var express = require('express');
var router = express.Router();
// 导入写好的注册/登录函数
const {
	regUser,
	login
} = require('../public/javascripts/login')

/* GET users listing. */
router.get('/', function(req, res, next) {
	// 获取客户端提交到服务器的用户信息
	const userInfo = req.body
	if(req.user){
		return res.cc('获取成功', 0, req.user)
	}
	// 获取到中间件的时间
	res.send('GET 请求成功');
});

/**
 * POST 用户注册
 * @param username  用户名
 * @param password  用户密码
 */
router.post('/add', (req, res, next) => {
	// 通过 req.body 获取请求体中包含的 url-encoded 格式的数据
	console.log(req.body)
	const userInfo = req.body
	//【步骤一】对客户端的数据进行校验
	if (userInfo.username == '' || userInfo.password == '') {
		return res.send({
			status: 1,
			msg: '用户名和密码不能为空'
		})
	}
	// 【步骤二】执行定义好的注册函数
	regUser(req, res)
});

/**
 * POST 用户登录
 * @param username  用户名
 * @param password  用户密码
 */
router.post('/login', (req, res, next) => {
	// 通过 req.body 获取请求体中包含的 url-encoded 格式的数据
	// console.log(req.body)
	const userInfo = req.body
	//对客户端的数据进行校验
	if (userInfo.username == '' || userInfo.password == '') {
		return res.send({
			status: 1,
			msg: '用户名和密码不能为空'
		})
	}
	// 执行定义好的登录函数
	login(req, res)
});





/* 模板 */
// // 在这里挂载对应的路由
// router.get('/get', (req, res) => {
//   // 通过 req.query 获取客户端通过查询字符串,发送到服务器的数据
//   const query = req.query
//   // 调用 res.send() 方法,向客户端响应处理的结果
//   res.send({
//     status: 0, // 0 表示处理成功,1 表示处理失败
//     msg: 'GET 请求成功!', // 状态的描述
//     data: query, // 需要响应给客户端的数据
//   })
// })

// // 定义 POST 接口
// router.post('/post', (req, res) => {
//   // 通过 req.body 获取请求体中包含的 url-encoded 格式的数据
//   const body = req.body
//   // 调用 res.send() 方法,向客户端响应结果
//   res.send({
//     status: 0,
//     msg: 'POST 请求成功!',
//     data: body,
//   })
// })

// // 定义 DELETE 接口
// router.delete('/delete', (req, res) => {
//   res.send({
//     status: 0,
//     msg: 'DELETE请求成功',
//   })
// })

module.exports = router;

login.js登录注册函数

// 导入数据库操作模块
const db = require('../../db/index')
// 导入 bcryptjs 加密包
const bcrypt = require('bcryptjs')
// 导入生成Token的包
const jwt = require('jsonwebtoken')
// 导入全局配置文件(里面有token的密钥)
const config = require('../../config')

/**
 * POST 用户注册
 * @param username  用户名
 * @param password  用户密码
 */
exports.regUser = (req, res) => {
	// 获取客户端提交到服务器的用户信息
	const userInfo = req.body
	// 定义sql语句,查询用户名是否被占用
	let sql = 'select * from ev_users where username=?'
	db.query(sql, [userInfo.username], (error, result) => {
		if (error) {
			return res.cc(error)
		}
		if (result.length > 0) {
			return res.cc('用户名已被占用!')
		}
		// 调用 bcrypt.hashSync() 对密码加密
		userInfo.password = bcrypt.hashSync(userInfo.password, 10)
		// 定义插入新用户的 SQL 语句
		let sql1 = 'insert into ev_users set ?'
		// 调用 db.query() 执行 sql 语句
		db.query(sql1, {
			username: userInfo.username,
			password: userInfo.password
		}, (error, result) => {
			if (error) return res.cc(error)
			// 判断影响行数是否为 1
			if (result.affectedRows !== 1) return res.cc('注册用户失败!')
			return res.cc('注册用户成功', 0, {
				username: userInfo.username
			})
		})
	})
}

/**
 * POST 登录的回调函数
 * @param username  用户名
 * @param password  用户密码
 */
exports.login = (req, res) => {
	console.log('user', req.user);
	// 接收表单的数据
	const userInfo = req.body
	// 定义 SQL 语句
	const sql = 'select * from ev_users where username=?'
	// 执行 SQL 语句,根据用户名查询用户的信息
	db.query(sql, userInfo.username, (err, result) => {
		// 执行 SQL 语句失败
		if (err) return res.cc(err)
		// 执行 SQL 语句成功,但是获取的数据条数不为1 也是失败的
		if (result.length !== 1) return res.cc('登录失败!')
		// 经过上方俩条判断条件,则证明执行 SQL 成功

		// TODO :判断密码是否正确
		const comRes = bcrypt.compareSync(userInfo.password, result[0].password)
		if (!comRes) return res.cc('登陆失败')
		// 在服务器端生成 Token 字符串
		const user = {
			...result[0], // 解构用户信息
			password: '', //密码等敏感信息置空
		}
		// 对用户的信息进行加密,生成 token 字符串 
		const tokenStr = jwt.sign(user, config.jwtSecretKey, {
			expiresIn: config.expiresIn //tonken 有效期
		})
		// 调用 res.send 将Token响应给客户端
		res.send({
			status: 0,
			data: {
				user: user,
				token: 'Bearer ' + tokenStr,
			},
			message: '登录成功!!!',
		})
	})
}

到此我们的登录和注册接口已经实现,

接口文档:

注册:post       http://127.0.0.1/users/add

           请求参数:username:用户名   

                             password:密码

登录:post       http://127.0.0.1/users/login

           请求参数:username:用户名   

                             password:密码

十、解析token中间件

在刚刚我没完成了token的生成,现在我们做一个中间件用来解析token,来对用户进行身份认证

 1.安装解析中间件

npm i express-jwt

2.在App.js 中引入

//token解析中间件 一定要在路由之前配置解析 Token 的中间件
const expressJWT = require('express-jwt')
//映入解密
const config = require('./config')

3.注册全局中间件并解析token

// 注册全局中间件  链式调用 unless 方法,接收一个配置对象,path 字段设置一个正则表达式,表示不需要 token 身份认证的路由前缀。
app.use(expressJWT({
	// 加密时设置的密钥
	secret: config.jwtSecretKey,
	// 设置算法
	algorithms: ['HS256'],
	// 无token请求不进行解析,并且抛出异常
	// credentialsRequired: false
}).unless({
	path: [
		'/users/add',
		'/users/login',
		{
			url: /^\/public\/.*/,
			methods: ['GET', 'POST']
		}
	]
	// path: ['/users/login','/users']
}))

4.注册全局错误中间件 当token失效时 返回信息

// 错误中间件 当token失效时 返回信息
app.use((err, req, res, next) => {
	if (err.name === 'UnauthorizedError') {
		res.status(401).send({
			status: 1,
			data: {},
			message: '身份认证失败!'
		});
	}
});

十一、CORS跨域中间件

注册登录接口写好了,但是使用的时候会有一个很严重的问题:不支持跨域请求。

解决接口跨域问题的方案主要有两种:

① CORS(主流的解决方案,推荐使用)

② JSONP(有缺陷的解决方案:只支持 GET 请求)

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

cors 是 Express 的一个第三方中间件。通过安装和配置 cors 中间件,可以很方便地解决跨域问题。

使用步骤分为如下 3 步:

① 运行 npm install cors 安装中间件

npm install cors

② 使用 const cors = require(‘cors’) 导入中间件

// 一定要在路由之前,配置 cors 这个中间件,从而解决接口跨域的问题
const cors = require('cors')

③ 在路由之前调用 app.use(cors()) 配置中间件

app.use(cors())

完整代码:(jsonp就不做过多解释了)

// 【必须在配置 cors 中间件之前,配置 JSONP 的接口】
app.get('/api/jsonp', (req, res) => {
	// TODO: 定义 JSONP 接口具体的实现过程
	// 1. 得到函数的名称
	const funcName = req.query.callback
	// 2. 定义要发送到客户端的数据对象
	const data = {
		name: 'zs',
		age: 22
	}
	// 3. 拼接出一个函数的调用
	const scriptStr = `${funcName}(${JSON.stringify(data)})`
	// 4. 把拼接的字符串,响应给客户端
	res.send(scriptStr)
})

// 一定要在路由之前,配置 cors 这个中间件,从而解决接口跨域的问题
const cors = require('cors')
app.use(cors())

注意事项:

①CORS 主要在服务器端进行配置。客户端浏览器无须做任何额外的配置,即可请求开启了CORS的接口。

②CORS在浏览器中有兼容。只有支持XMLHttpRequest Level2的浏览器,才能正常访问开启了CORS的服务端接口(例如:IE10+、Chrome4+、FireFox3.5+)。

1、CORS 响应头部 - Access-Control-Allow-Origin

如果指定了 Access-Control-Allow-Origin 字段的值为通配符 *,表示允许来自任何域的请求,示例代码如下:

res.setHeader('Access-Control-Allow-Origin','*')

2、CORS 响应头部 - Access-Control-Allow-Headers

默认情况下,CORS 仅支持客户端向服务器发送如下的 9 个请求头:
Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width 、Content-Type (值仅限于 text/plain、multipart/form-data、application/x-www-form-urlencoded 三者之一)
如果客户端向服务器发送了额外的请求头信息,则需要在服务器端,通过 Access-Control-Allow-Headers 对额外的请求头进行声明,否则这次请求会失败!

 

// 允许客户端额外向服务器发送 Content-Type 请求头和 X-Custom-Header 请求头
// 注意: 多个请求头之间使用英文的逗号进行分割
res.setHeader('Access-Control-Allow-Headers ''Content-Type X-Custom-Header')

3、CORS 响应头部 - Access-Control-Allow-Methods

默认情况下,CORS 仅支持客户端发起 GET、POST、HEAD 请求。
如果客户端希望通过 PUT、DELETE 等方式请求服务器的资源,则需要在服务器端,通过 Access-Control-Alow-Methods来指明实际请求所允许使用的 HTTP 方法。示例代码如下:

// 只允许 POST、GET、DELETE、HEAD 请求方法
res,setHeader('Access-Control-A1low-Methods','POST,GET,DELETE,HEAD')
 // 允许所有的 HTTP 请求方法
 res,setHeader('Access-Control-A1low-Methods','*')

4、 CORS请求的分类

客户端在请求 CORS 接口时,根据 请求方式和请求头的不同,可以将 CORS 的请求分为两大类,分别是:
① 简单请求
② 预检请求

5、 简单请求

同时满足以下两大条件的请求,就属于简单请求:
① 请求方式:GET、POST、HEAD 三者之一
② HTTP 头部信息不超过以下几种字段:无自定义头部字段、Accept、Accept-Language、Content-Language、DPR、Downlink、Save-Data、Viewport-Width、Width 、Content-Type(只有三个值application/x-www-form-urlencoded、multipart/form-data、text/plain)

6、预检请求

只要符合以下任何一个条件的请求,都需要进行预检请求:
① 请求方式为 GET、POST、HEAD 之外的请求 Method 类型
② 请求头中包含自定义头部字段
③ 向服务器发送了 application/json 格式的数据

在浏览器与服务器正式通信之前,浏览器会先发送 OPTION 请求进行预检,以获知服务器是否允许该实际请求,所以这一次的 OPTION 请求称为“预检请求”。服务器成功响应预检请求后,才会发送真正的请求,并且携带真实数据。

7.、简单请求和预检请求的区别

简单请求的特点:客户端与服务器之间只会发生一次请求。
预检请求的特点:客户端与服务器之间会发生两次请求,OPTION 预检请求成功之后,才会发起真正的请求。

2、最后附上app.js完整代码 

// 导入 express
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

// 引入路由模块
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

// 创建服务器实例
var app = express();

app.use(logger('dev'));

// 处理 application/json
app.use(express.json());

// 配置解析表单数据的中间件 处理 x-www-form-urlencoded
app.use(express.urlencoded({
	extended: false
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

//token解析中间件 一定要在路由之前配置解析 Token 的中间件
const expressJWT = require('express-jwt')
//映入解密
const config = require('./config')
// 注册全局中间件  链式调用 unless 方法,接收一个配置对象,path 字段设置一个正则表达式,表示不需要 token 身份认证的路由前缀。
app.use(expressJWT({
	// 加密时设置的密钥
	secret: config.jwtSecretKey,
	// 设置算法
	algorithms: ['HS256'],
	// 无token请求不进行解析,并且抛出异常
	// credentialsRequired: false
}).unless({
	path: [
		'/users/add',
		'/users/login',
		{
			url: /^\/public\/.*/,
			methods: ['GET', 'POST']
		}
	]
	// path: ['/users/login','/users']
}))

// 【必须在配置 cors 中间件之前,配置 JSONP 的接口】
app.get('/api/jsonp', (req, res) => {
	// TODO: 定义 JSONP 接口具体的实现过程
	// 1. 得到函数的名称
	const funcName = req.query.callback
	// 2. 定义要发送到客户端的数据对象
	const data = {
		name: 'zs',
		age: 22
	}
	// 3. 拼接出一个函数的调用
	const scriptStr = `${funcName}(${JSON.stringify(data)})`
	// 4. 把拼接的字符串,响应给客户端
	res.send(scriptStr)
})

// 一定要在路由之前,配置 cors 这个中间件,从而解决接口跨域的问题
const cors = require('cors')
app.use(cors())

//定义第一个全局中间件
app.use((req, res, next) => { //res用于返回客户端 req客户端的请求参数  next() 提交给下一个中间件
	// 只允许  请求方法
	res.setHeader('Access-Control-Allow-Methods', 'POST, GET, DELETE,HEAD')
	// 响应头 允许所有的 HTTP 请求方法
	res.setHeader('Access-Control-Allow-Methods', '*')
	// 如果指定了 Access-Control-Allow-Origin 字段的值为通配符 *,表示允许来自任何域的请求
	res.setHeader('Access-Control-Allow-Origin', '*')
	// res.setHeader("Access-Control-Allow-Headers", "content-type,Authorization");
	next();
})



//封装错误处理函数
app.use((req, res, next) => {
	res.cc = function(err, status = 1, data = {}) {
		res.send({
			status,
			data,
			message: err instanceof Error ? err.message : err
		})
	}
	next()
})

// 错误中间件 当token失效时 返回信息
app.use((err, req, res, next) => {
	if (err.name === 'UnauthorizedError') {
		res.status(401).send({
			status: 1,
			data: {},
			message: '身份认证失败!'
		});
	}
});

// 挂载路由
app.use('/', indexRouter);

/* 用户路由 */
app.use('/users', usersRouter);

module.exports = app;

 跨域这部分和jsonp参考了以下文章 

【nodejs-03】黑马nodejs学习笔记03-express中间件与跨域_简单长庚的博客-CSDN博客文章来源地址https://www.toymoban.com/news/detail-672639.html

到了这里,关于基于NodeJs+Express+MySQL 实现实现登录注册接口+token生成与解析验证+跨域-CORS的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • WEB通讯技术。前端实现SSE长连接,nodejs+express搭建简单服务器,进行接口调试,通过curl请求数据

    长连接(Keep-Alive)是一种HTTP/1.1的持久连接技术,它允许客户端和服务器在一次TCP连接上进行多个HTTP请求和响应,而不必为每个请求/响应建立和断开一个新的连接。长连接有助于减少服务器的负载和提高性能。 长连接的HTTP请求方法与普通HTTP请求方法相同,可以使用GET、P

    2024年02月09日
    浏览(53)
  • node.js(express.js)+mysql实现登录功能

    实现步骤 1.检测表单数据是否合法 2.根据用户名查询用户的数据 3.判断用户输入的密码是否正确 4.生成JWT 的 Token 字符串 登录接口完整代码如下:controllers/user.js文件 一、检测登录表单的数据是否合法 1)安装 jOi 包,为表单中携带的每个数据项,定义验证规则: (2)安装 @e

    2024年01月19日
    浏览(43)
  • 30天精通Nodejs--第二十天:express-操作mysql

    在Node.js中使用Express框架进行开发时,经常会需要持久化数据,与关系型数据库MySQL的集成是至关重要的一步。本文将详细阐述如何在Express项目中连接MySQL数据库,并通过实例代码演示如何执行基本的增删改查(CRUD)操作。

    2024年01月18日
    浏览(40)
  • 基于微信评选投票小程序毕业设计作品成品(11)用户注册和登录接口

    博主介绍: 《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程,免费 项目配有对应开发文档、开题报告、任务书、PPT、论文模版

    2024年02月07日
    浏览(51)
  • 基于微信电子书小说阅读小程序毕业设计成品作品(12)用户注册和登录接口

    博主介绍: 《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程,免费 项目配有对应开发文档、开题报告、任务书、PPT、论文模版

    2024年02月08日
    浏览(55)
  • 【Unity+MySQL】实现注册登录系统(封装版)

    接着 上篇文章的注册登录系统,这篇文章将MySQL相关操作封装,在Unity交互脚本中直接调用封装的方法。 编写一个DBConnector脚本,封装MySQL中常用的操作,如连接数据库、关闭数据库、查询数据库、除查询外的插入、更新、删除等操作。 编写一个User脚本用于封装用户注册、登

    2024年02月05日
    浏览(48)
  • 【Unity+MySQL】实现简单的注册登录系统

    确保这两个软件都能够在你的计算机上良好地运行。 镜像地址:http://mirrors.sohu.com/mysql/MySQL-8.0/ 下载完成后双击运行msi文件。 Next→ Next→ 选择自定义安装, Next→ 选择安装路径, Next→ Install安装, 安装完成,Finish。 此电脑→计算机→属性, 关于→高级系统设置, 高级→环

    2024年02月05日
    浏览(61)
  • 【Unity+MySQL】实现注册登录系统(升级版)

    接着 上篇文章所谈到的系统缺陷,这篇文章进行升级解决。 问题 :注册界面与登录界面是同一个界面,导致用户输入用户密码进行注册后,即可点击登录。 解决 :在同一个场景中分别创建注册界面和登录界面,使用SetActive控制注册/登录成功后UI的显示与隐藏。 整体的UI框

    2024年02月09日
    浏览(50)
  • 使用JSP+Servlet+MySQL实现登录注册功能

    ✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏: Java从入门到精通 ✨特色专栏: MySQL学习 🥭本文内容:使用JSP+Servlet+MySQL实现登录注册功能 📚个人知识库: Leo知识库,欢迎大家访问 大家好,

    2024年02月04日
    浏览(50)
  • 100 行代码实现用户登录注册与 RESTful 接口 - 手把手教程附 Python 源码

    在开发大多数应用时,用户系统都是必不可少的部分,而我们总是需要开发围绕用户的登录,注册,获取,更新等接口。在这篇文章将带你用一百多行代码简洁地实现一套这样的用户鉴权与 RESTful 接口,并使用 Session 来处理用户的登录登出 我们将使用 UtilMeta 框架 完成接口开

    2024年02月19日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包