Node开发后台API接口项目

1.初始化项目

1-1.创建项目

  1. 新建api_server文件夹,运行
npm init -y
  1. 安装exoress
npm i express
  1. 在项目中新建app.js作为整个项目的入口文件,并创建服务器
// 导入模块
const express = require('express')




// 创建服务器
const app = express()


// 启动服务器
app.listen(80,(req,res)=>{
    console.log(run in localhost);
})

1-2.配置cors

  1. 安装cors中间件
npm i cors
  1. 在app.js中导入中间件
// 导入中间件
const cors = require('cors')
  1. 注册cors中间件
// 注册全局中间件
app.use(cors())

1-3.配置解析表单数据的中间件

  1. 配置解析application/x-www-form-urlencoided表单数据的中间件
  2. urlencoded()是express内置的方法
app.use(express.urlencoded({extended:false}))

2.初始化路由

2-1.初始化路由相关的文件夹

  1. 在项目根目录中,新建router文件夹,用来存放所有的路由模块

路由模块中,只存放客户端的请求与处理函数之间的映射关系

  1. 在项目根目录中,新建router_handler文件夹,用来存放所有的路由处理函数模块

路由处理函数模块中,专门负责存放每个路由对应的处理函数

2-2.初始化用户路由模块

  1. router文件夹中,新增use.js文件,作为用户的路由模块,初始化代码如下
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
  1. app.js中,导入并且使用用户路由模块
const userRouter = require('./router/user')
app.use('/api',userRouter)

2-3.抽离路由函数中的处理函数

目的 :为了保证路由模块的纯粹性,所有的路由处理函数,必须抽离到对应的路由处理函数模块中

  1. /router_handler/user.js 中,使用 exports 对象 , 分别向外共享两个 路由处理函数
// 定义一些路由处理函数供路由模块使用
// 注册用户的处理函数
exports.reguser = (req,res)=>{
    res.send('reguser ok')
}
// 登录的处理函数
exports.login = (req,res)=>{
    res.send('login ok')
}
  1. 将/router/user.js中的代码修改为如下结构
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

3.注册接口

3-1.新建 ev_users 表

  1. 新建my_db_01 数据库中,新建 ev_users 表

3-2.安装并且配置mysql模块

  1. 运行如下命令,安装 mysql 模块
npm i mysql
  1. 在项目根目录中新建 /db/index.js 文件,在此自定义模块中创建数据库的连接对象
const mysql = require('mysql')

// 创建数据库连接对象
const db = mysql.createPool({
    host:'127.0.0.1',
    user:'root',
    password:'qwer',
    database:'my_db_01'
})

module.exports = db

3-3.注册

3-3-1.实现步骤

  1. 检验表单数据是否合法
  2. 检验用户名是否被占用
  3. 对密码进行加密处理
  4. 插入新用户

3-3-2.检验表单数据是否合法

  1. 判断用户名和密码是否为空
 // 获取客户端提交到服务器的用户信息
    const userinfo = req.body
    // 对表单中的数据进行判断
    if(!userinfo.username || !userinfo.password){
        return res.send({
            status:1,
            message:'用户可或者密码不能为空'
        })
    }

3-3-3.检验用户名是否被占用

  1. 导入数据库操作模块(在router_handler下面的user.js中)
// 导入数据库操作模块
const db = require('../db/index')
  1. 定义sql语句
// 注册用户的处理函数
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')
}
  1. 执行sql语句并根据结果判断用户名是否被占用
 // 判断用户是否被占用
        if(results.length > 0 ){
            return res.send({
                status:1,
                message:'用户名被占用'
            })
        }
        // 用户名可以使用,待会写

3-3-4.对密码进行加密处理

为了保证密码的安全性,不建议在数据库以明文的形式保存用户密码,推荐对密码进行加密存储
在当前项目中,使用berypjs 对用户密码进行加密,优点:
1.加密之后的密码,无法被逆向破解
2.同一明文密码多次加密,得到的加密结果各不相同,保证了安全性

  1. 运行以下命令安装bcryptjs
npm i bcryptjs
  1. 在**/router handler/user.js中,导入bcrypt.js**
// 导入bcryptjs
const bcrypt = require('bcryptjs')
  1. 在注册用户的处理函数中,确认用户名可用之后,调用berypt .hashSync(明文密码,随机盐的长度)方法,对用户的密码进行加密处理:
在这里插入代码片

3-3-5.插入新用户

  1. 定义插入用户的sql语句
const sql = 'insert into ev_users set ?'
  1. 调用db.query()执行sql语句,插入新用户
// 定义插入新用户的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:'注册成功'})
        })
    })

4.代码优化

4-1.优化res.send()代码

在处理函数中,需要多次调用res. send()向客户端响应处理失败的结果, 为了简化代码,可以手动封装一个res.cw()函数

  1. 在app.js 中,所有路由之前,声明一一个全局中间件,为res对象挂载-一个res.cc() 函数:
// 代码优化,在路由前面封装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()
})

4-2.验证规则

  1. 在router_handler下面的router.js中添加下面规则代码
// 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('密码不合法')
    }

5.登录接口

5-1.实现步骤

  1. 检测表单数据是否合法
  2. 根据用户查询用户的数据
  3. 判断用户输入的密码是否正确
  4. 生成JWT的token数据

5-2.检测表单数据是否合法

  1. 将/router/user.js中的登录路由修改如下
// 登录的处理函数
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('登陆成功')
}

5-3.根据用户名查询用户的数据

  1. 定义sql语句
// 3-1.定义sql语句
    const sql = 'select * from ev_users where username:?'
  1. 将/router/user.js中的登录路由修改如下
// 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('登陆成功')

5-4.判断用户输入的密码是否正确

核心实现思路:调用berypt . compareSyne(用户提交的密码,数据库中的密码)方法比较密码是否一致
返回值是布尔值(true- 致,false 不一致)
具体实现代码如下:

// 4判断用户输入的密码是否正确
    //拿着用户输入的密码,和数据库中存储的密码进行对比
    const conpareResult = bcrypt.compareSync(userinfo.password,results[0],password)
    //如果对比的结果等于false, 则证明用户输入的密码错误
    if(!conpareResult){
        return res.cw('登陆失败')
    }
    res.send('登陆成功')
}

5-5.生成JWT的token字符串

为了不让token把生成的字符串中的密码头像中的值返回给客户端,在生成token的时候把他们剔除 了

  1. 通过es6语法,快速剔除密码和头像的值
// 5-1.剔除密码和头像、
    const user = {...results[0],password:'',user_pic:''}
    // console.log(user);
  1. 运行命令安装生成token字符串的包jsonwebtoken包
npm i jsonwebtoken
  1. 在**/router_handler/user.js模块的头部区域,导入jsonwebtoken包**
// 导入生成token的包
const jwt = require('jsonwebtoken')
// 导入全局配置文件
const config = require('../config')
  1. 根目录创建config.js文件,并向外共享加密和还原token的jwtSecretKey字符串
// 这是一个全局的配置文件
module.exports = {
    // 加密密钥
    jwtSecretKey:'liuq520 ^_^'
}
  1. 将用户信息对象加密成token字符串
// 5-2.对用户信息进行加密,生成token字符串
    const tokenStr = jwt.sign(user,config.jwtSecretKey,{expiresIn:'10h'})
  1. 将生成的token字符串响应给客户端
res.send({
        status:0,
        message:'登陆成功',
        token:'Bearer ' + tokenStr
        })

5-6.配置解析token的中间件

  1. 安装express-jwt中间件
npm i express-jwt@5.3.3
  1. 在app.js中注册路由之前,配置解析token的中间件
app.use(expressJWT({secret:config.jwtSecretKey}).unless({path:[/^\/api\]}))
  1. 在app.js中的错误级别中间件里面捕获并且处理token认证失败后的错误
// 定期错误级别的中间件
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)
})

6.个人中心(开发获取用户的基本信息的接口)

6-1.初始路由模块

  1. 在router目录下创建userinfo.js路由模块,并且初始化如下代码
const express = require('express')
const router = express.Router()

// 注册新用户
router.get('/userinfo',(req,res)=>{
    res.send('ok')
})

module.exports = router
  1. 在app.js中导入并使用个人中心的路由模块
// 导入userinfo的路由模块
const userinfoRouter = require('./router/userinfo')
app.use('/my',userinfoRouter)

6-2.初始路由处理函数的模块

  1. 创建/router_handler/userinfo.js路由处理函数,并且初始化如下代码
exports.getUserInfo = (req,res)=>{
    res.send('ok')
}
  1. 修改/router/userinfo.js中的代码
const express = require('express')
const router = express.Router()
// 导入事件处理函数
const userinfo_handler = require('../router_handler/userinfo')

// 注册新用户
router.get('/userinfo',userinfo_handler.getUserInfo)

module.exports = router

6-3.获取用户的基本信息

  1. 导入数据库在处理函数userinfo.js中
const db = require('../db/index')
  1. 定义sql语句
// 定义sql语句,根据用户id,查询用户基本信息
    const sql = 'select id , username , nickname , email , user_pic from ev_users where id=?'
  1. 调用db.query()执行sql语句
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]
        })
    })

7.个人中心(更新用户信息的接口)

7-1.定义路由和处理函数

  1. 在/router/userinfo.js 模块中,新增更新用户基本信息的路由:
    // 更新用户信息的接口
router.post('/userinfo',userinfo_handler.updateUserInfo)
  1. 在/router. handler/userinfo.js模块中,定义并向外共享更新用户基本信息的路由处理函数:
    // 1.更新用户信息
    exports.updateUserInfo = (req,res)=>{
        res.send('ok')
    }

7-2.验证表单数据 (nickname和email)

  1. 直接在处理函数中的userinfo.js 的updateInfo添加代码
// 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')
    }

7-3.实现更新用户基本信息的功能

  1. 定义待执行的sql语句
    // 2-1.定义sql语句
    const sql = 'update ev_users set ? where id=?'
  1. 调用db.query()执行sql语句
// 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('修改用户信息成功')

    })

8.个人中心(重置密码的接口)

8-1.定义路由和处理函数

  1. . 在/router/userinfo.js 模块中,新增重置密码的路由
// 3.重置密码的接口
router.post('/updatepwd',userinfo_handler.updatePassword)
  1. 在/router. .handler/userinfo.js模块中,定义并向外共享重置密码的路由处理函数:
    // 1.重置密码
    exports.updatePassword = (req,res)=>{
        res.send('ok')
    }

8-2.验证表单数据

// 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')
    
    }

8-3.实现重置密码功能

  1. 定义待执行的sql语句
    // 2-1.定义sql语句
    const sql = 'update ev_users set ? where id=?'
  1. 调用db.query()执行sql语句
//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('修改用户信息成功')
    })
  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

忧郁火龙果

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值