npm init -y
npm i express
// 导入模块
const express = require('express')
// 创建服务器
const app = express()
// 启动服务器
app.listen(80,(req,res)=>{
console.log(run in localhost);
})
npm i cors
// 导入中间件
const cors = require('cors')
// 注册全局中间件
app.use(cors())
app.use(express.urlencoded({extended:false}))
路由模块中,只存放客户端的请求与处理函数之间的映射关系
路由处理函数模块中,专门负责存放每个路由对应的处理函数
const express = require('express')
const router = express.Router()
// 注册新用户
router.post('/reguser',(req,res)=>{
res.send('ok')
})
// 登录
router.post('/losin',(req,res)=>{
res.send('ok')
})
module.exports = router
const userRouter = require('./router/user')
app.use('/api',userRouter)
目的 :为了保证路由模块的纯粹性,所有的路由处理函数,必须抽离到对应的路由处理函数模块中
// 定义一些路由处理函数供路由模块使用
// 注册用户的处理函数
exports.reguser = (req,res)=>{
res.send('reguser ok')
}
// 登录的处理函数
exports.login = (req,res)=>{
res.send('login ok')
}
const express = require('express')
const router = express.Router()
// 导入用户路由处理函数的模块
const userHandler = require('../router_handler/user')
// 注册新用户
router.post('/reguser',userHandler.reguser)
// 登录
router.post('/login',userHandler.login)
module.exports = router
npm i mysql
const mysql = require('mysql')
// 创建数据库连接对象
const db = mysql.createPool({
host:'127.0.0.1',
user:'root',
password:'qwer',
database:'my_db_01'
})
module.exports = db
// 获取客户端提交到服务器的用户信息
const userinfo = req.body
// 对表单中的数据进行判断
if(!userinfo.username || !userinfo.password){
return res.send({
status:1,
message:'用户可或者密码不能为空'
})
}
// 导入数据库操作模块
const db = require('../db/index')
// 注册用户的处理函数
exports.reguser = (req,res)=>{
// 获取客户端提交到服务器的用户信息
const userinfo = req.body
// 对表单中的数据进行判断
if(!userinfo.username || !userinfo.password){
return res.send({
status:1,
message:'用户可或者密码不能为空'
})
}
// 定义sql语句,查询用户名是否被占用
const sqlStr = 'select * from ev_users where username=?'
db.query(sqlStr,userinfo.username,(err,results)=>{
// 执行语句失败
if(err){
return res.send({
status:1,
message:err.message
})
}
// 判断用户是否被占用
if(results.length > 0 ){
return res.send({
status:1,
message:'用户名被占用'
})
}
// 用户名可以使用,待会写
})
res.send('reguser ok')
}
// 判断用户是否被占用
if(results.length > 0 ){
return res.send({
status:1,
message:'用户名被占用'
})
}
// 用户名可以使用,待会写
为了保证密码的安全性,不建议在数据库以明文的形式保存用户密码,推荐对密码进行加密存储
在当前项目中,使用berypjs 对用户密码进行加密,优点:
1.加密之后的密码,无法被逆向破解
2.同一明文密码多次加密,得到的加密结果各不相同,保证了安全性
npm i bcryptjs
// 导入bcryptjs
const bcrypt = require('bcryptjs')
在这里插入代码片
const sql = 'insert into ev_users set ?'
// 定义插入新用户的sql语句
const sql = 'insert into ev_users set ?'
// 调用db.query()执行sql语句,插入新用户
db.query(sql,{username:userinfo.username,password:userinfo.password},(err,results)=>{
// 判断语句是否执行成功
if(err){return res.send({status:1,message:err.message})}
// 判断影响行数是否为1
if(results.affectedRows !==1){return res.send({status:1,message:'注册失败,请稍后再试'})}
// 注册成功
res.send({status:0 , message:'注册成功'})
})
})
在处理函数中,需要多次调用res. send()向客户端响应处理失败的结果, 为了简化代码,可以手动封装一个res.cw()函数
// 代码优化,在路由前面封装res.cw函数
app.use((req,res,next)=>{
//status 的值默认为1 ,表示注册失败
//err 的值可能是个错误对象也可能是个字符串
res.cw = (err,status = 1)=>{
res.send({
status,
message:err instanceof Error ? err.message : err
})
}
next()
})
// 3.对表单数据进行验证看是否合法
// 用户名由英文、数字组成
const userTest = /^[0-9a-zA-Z]\w{1,11}$/
// 密码由英文、数字组成
const pwdTest = /^[0-9a-zA-Z]\w{2,11}$/
// console.log(!userTest.test(userinfo.username));
// console.log(!pwdTest.test(userinfo.password));
if (!userTest.test(userinfo.username)) {
return res.cw('用户名不合法')
} else if(!pwdTest.test(userinfo.password)){
return res.cw('密码不合法')
}
// 登录的处理函数
exports.login = (req, res) => {
// 1.获取客户端提交到服务器的用户信息
const userinfo1 = req.body
// 2.对表单数据进行验证看是否合法
// 用户名由英文、数字组成
const userTest = /^[0-9a-zA-Z]\w{1,11}$/
// 密码由英文、数字组成
const pwdTest = /^[0-9a-zA-Z]\w{1,11}$/
if (!userTest.test(userinfo1.username)) {
return res.cw('用户名不合法')
} else if(!pwdTest.test(userinfo1.password)){
return res.cw('密码不合法')
}
res.send('登陆成功')
}
// 3-1.定义sql语句
const sql = 'select * from ev_users where username:?'
// 3.根据用户名查询用户的数据
// 3-1.定义sql语句
const sql = 'select * from ev_users where username:?'
// 3-2.执行sql语句,查询用户数据
db.query(sql,userinfo.username,(err,results)=>{
// 3-3.执行sql语句失败
if(err){res.cw(err)}
// 3-4.执行sql语句成功,但是得到的数据不等于1
if(results.length != 1){
res.cw('登陆失败')
}
})
res.send('登陆成功')
核心实现思路:调用berypt . compareSyne(用户提交的密码,数据库中的密码)方法比较密码是否一致
返回值是布尔值(true- 致,false 不一致)
具体实现代码如下:
// 4判断用户输入的密码是否正确
//拿着用户输入的密码,和数据库中存储的密码进行对比
const conpareResult = bcrypt.compareSync(userinfo.password,results[0],password)
//如果对比的结果等于false, 则证明用户输入的密码错误
if(!conpareResult){
return res.cw('登陆失败')
}
res.send('登陆成功')
}
为了不让token把生成的字符串中的密码和头像中的值返回给客户端,在生成token的时候把他们剔除 了
// 5-1.剔除密码和头像、
const user = {...results[0],password:'',user_pic:''}
// console.log(user);
npm i jsonwebtoken
// 导入生成token的包
const jwt = require('jsonwebtoken')
// 导入全局配置文件
const config = require('../config')
// 这是一个全局的配置文件
module.exports = {
// 加密密钥
jwtSecretKey:'liuq520 ^_^'
}
// 5-2.对用户信息进行加密,生成token字符串
const tokenStr = jwt.sign(user,config.jwtSecretKey,{expiresIn:'10h'})
res.send({
status:0,
message:'登陆成功',
token:'Bearer ' + tokenStr
})
npm i express-jwt@5.3.3
app.use(expressJWT({secret:config.jwtSecretKey}).unless({path:[/^\/api\]}))
// 定期错误级别的中间件
app.use((err,req,res,next)=>{
//验证失败导致的错误
if(err instanceof joi.ValidationError){return res.cw(err)}
// 身份认证失败后的错误
if(err.name === 'UnauthorizedError'){return res.cw('身份认证失败')}
// 未知错误
res.cw(err)
})
const express = require('express')
const router = express.Router()
// 注册新用户
router.get('/userinfo',(req,res)=>{
res.send('ok')
})
module.exports = router
// 导入userinfo的路由模块
const userinfoRouter = require('./router/userinfo')
app.use('/my',userinfoRouter)
exports.getUserInfo = (req,res)=>{
res.send('ok')
}
const express = require('express')
const router = express.Router()
// 导入事件处理函数
const userinfo_handler = require('../router_handler/userinfo')
// 注册新用户
router.get('/userinfo',userinfo_handler.getUserInfo)
module.exports = router
const db = require('../db/index')
// 定义sql语句,根据用户id,查询用户基本信息
const sql = 'select id , username , nickname , email , user_pic from ev_users where id=?'
db.query(sql,req.user.id,(err,results)=>{
// 解析成功后的token的值会挂在到req上
// 执行sql失败
if(err){
return res.send(err)
}
if(results.length !== 1){
res.send('获取用户信息失败')
}
res.send({
status:0,
message:'获取用户信息成功',
data:results[0]
})
})
// 更新用户信息的接口
router.post('/userinfo',userinfo_handler.updateUserInfo)
// 1.更新用户信息
exports.updateUserInfo = (req,res)=>{
res.send('ok')
}
// 1.更新用户信息
exports.updateUserInfo = (req,res)=>{
// 1.获取客户端提交到服务器的用户信息
const userinfo = req.body
// 验证表单数据 (nickname和email)
// 昵称由英文、数字组成
const nicknameTest = /^[0-9a-zA-Z]\w{1,11}$/
// 邮箱由英文、数字组成
const emailTest = /^[0-9a-zA-Z]\w{2,11}$/
// console.log(!userTest.test(userinfo.username));
// console.log(!pwdTest.test(userinfo.password));
if (!nicknameTest.test(userinfo.nickname)) {
return res.cw('昵称不合法')
} else if(!emailTest.test(userinfo.email)){
return res.cw('邮箱不合法')
}
res.send('ok')
}
// 2-1.定义sql语句
const sql = 'update ev_users set ? where id=?'
// 2-2. 调用db.query()执行sql语句
db.query(sql,[req.body,req.body.id],(err,results)=>{
// 执行sql语句失败
if(err){return res.send(err)}
// z执行sql语句成功,但是行数不为1
if(results.affectedRows != 1){return res.send('修改用户信息失败')}
// 修改用户信息成功、
return res.send('修改用户信息成功')
})
// 3.重置密码的接口
router.post('/updatepwd',userinfo_handler.updatePassword)
// 1.重置密码
exports.updatePassword = (req,res)=>{
res.send('ok')
}
// 1.重置密码
exports.updatePassword = (req,res)=>{
// 1.获取客户端提交到服务器的用户信息
const userinfo = req.body
// 验证表单数据 (nickname和email)
// 新密码由英文、数字组成
const newPwd = /^[0-9a-zA-Z]\w{1,11}$/
if (!newPwd.test(userinfo.password)) {
return res.send('新密码不合法')
}
return res.send('ok')
}
// 2-1.定义sql语句
const sql = 'update ev_users set ? where id=?'
//2.实现更新用户密码功能
const sql = 'update ev_users set ? where id=?'
// 2-2. 调用db.query()执行sql语句
db.query(sql,[req.body,req.body.id],(err,results)=>{
// 执行sql语句失败
if(err){return res.send(err)}
// z执行sql语句成功,但是行数不为1
if(results.affectedRows != 1){return res.send('修改密码失败')}
// 修改用户信息成功、
return res.send('修改用户信息成功')
})