• Node开发后台API接口项目


    1.初始化项目

    1-1.创建项目

    1. 新建api_server文件夹,运行
    npm init -y
    
    • 1
    1. 安装exoress
    npm i express
    
    • 1
    1. 在项目中新建app.js作为整个项目的入口文件,并创建服务器
    // 导入模块
    const express = require('express')
    
    
    
    
    // 创建服务器
    const app = express()
    
    
    // 启动服务器
    app.listen(80,(req,res)=>{
        console.log(run in localhost);
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    1-2.配置cors

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

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

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

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    1. app.js中,导入并且使用用户路由模块
    const userRouter = require('./router/user')
    app.use('/api',userRouter)
    
    • 1
    • 2

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.注册接口

    3-1.新建 ev_users 表

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

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

    1. 运行如下命令,安装 mysql 模块
    npm i mysql
    
    • 1
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    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:'用户可或者密码不能为空'
            })
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

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

    1. 导入数据库操作模块(在router_handler下面的user.js中)
    // 导入数据库操作模块
    const db = require('../db/index')
    
    • 1
    • 2
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    1. 执行sql语句并根据结果判断用户名是否被占用
     // 判断用户是否被占用
            if(results.length > 0 ){
                return res.send({
                    status:1,
                    message:'用户名被占用'
                })
            }
            // 用户名可以使用,待会写
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

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

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

    3-3-5.插入新用户

    1. 定义插入用户的sql语句
    const sql = 'insert into ev_users set ?'
    
    • 1
    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:'注册成功'})
            })
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    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()
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    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('密码不合法')
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    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('登陆成功')
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

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

    1. 定义sql语句
    // 3-1.定义sql语句
        const sql = 'select * from ev_users where username:?'
    
    • 1
    • 2
    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('登陆成功')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

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

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

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

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

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

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

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

    1. 安装express-jwt中间件
    npm i express-jwt@5.3.3
    
    • 1
    1. 在app.js中注册路由之前,配置解析token的中间件
    app.use(expressJWT({secret:config.jwtSecretKey}).unless({path:[/^\/api\]}))
    
    • 1
    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)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. 在app.js中导入并使用个人中心的路由模块
    // 导入userinfo的路由模块
    const userinfoRouter = require('./router/userinfo')
    app.use('/my',userinfoRouter)
    
    • 1
    • 2
    • 3

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

    1. 创建/router_handler/userinfo.js路由处理函数,并且初始化如下代码
    exports.getUserInfo = (req,res)=>{
        res.send('ok')
    }
    
    • 1
    • 2
    • 3
    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

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

    1. 导入数据库在处理函数userinfo.js中
    const db = require('../db/index')
    
    • 1
    1. 定义sql语句
    // 定义sql语句,根据用户id,查询用户基本信息
        const sql = 'select id , username , nickname , email , user_pic from ev_users where id=?'
    
    • 1
    • 2
    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]
            })
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

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

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

    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')
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

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

    1. 定义待执行的sql语句
        // 2-1.定义sql语句
        const sql = 'update ev_users set ? where id=?'
    
    • 1
    • 2
    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('修改用户信息成功')
    
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

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

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

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

    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')
        
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

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

    1. 定义待执行的sql语句
        // 2-1.定义sql语句
        const sql = 'update ev_users set ? where id=?'
    
    • 1
    • 2
    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('修改用户信息成功')
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    大数据概述、前世今生、处理流程、学习路线、开发工具详解
    后Kubernetes时代,每个行业需要定制化的符合自身的云原生战略
    【系统稳定性】1.6 黑屏(三)
    Python数据分析与机器学习在金融风控中的应用
    Linux常见命令手册
    C#底层库--随机数生成类
    「Redis数据结构」RedisObject
    如何反编译去掉安卓应用的版本更新功能
    Elasticserch教程(35) ik中文分词器+pinyin拼音分词器+同义词
    源码解析springbatch的job是如何运行的?
  • 原文地址:https://blog.csdn.net/LQlove1/article/details/126648958