小白重生之我在Node服务器的日子

前言:黑夜冷风吹起无聊的思緒,那些伤痕像細雨一样密布身体每个细胞

START-从零到壹

在很久很久以前......,多的不说,少的不唠,咱先创建个文件夹进行初始化再说, npm init -y,工欲善其事必先利其器,在终端安装好一下工具(express 是基于 Node.js 平台,快速、开放、极简的 Web 开发框架,cors 处理跨域请求,mysql数据库,我们使用的是MySQL Workbench 8.0CE)

npm i express@4.17.1
npm i cors@2.8.5
npm i mysql@2.18.1
复制代码

安装好插件后,在根目录创建app.js去开启服务器(先尝试一下最简单的服务器=> 运行方法:在终端输入命令 node .\app.js 即可运行服务器了)

// app.js
const express = require("express")
const app = express()
app.listen(2000,()=>{
    console.log('api server running at http://127.0.0.1:2000');
})

复制代码

控制台这样显示就是服务器已经在运行了哈

跨域

通常我们会碰到跨域的问题(出于浏览器的同源策略限制),当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域

// 解决跨域
// app.js
const cors=require("cors")
app.use(cors())
// 解析表单数据(只能解析application/x-www-form-urlencoded格式的数据),必须写在路由之前
app.use(express.urlencoded({ extended: false })) 

复制代码

路由

我们会在根目录下创建两个文件夹(router,router_handle)在对路由进行分工

// router/user.js
const express = require("express")
const route = express.Router()  // 路由的实例化

// 注册用户路由
route.post('/reguser', (req, res) => {
    res.send('reguser ok')
})
// 登录用户路由
route.post('/login', (req, res) => {
    res.send('login ok')
})
// 将挂载好的路由暴露出去
module.exports = route
复制代码

我们做好以上后,路由还没通呢,需要在app.js中使用该路由

// 导入路由 app.js
const router = require("./router/user")
app.use('/api', router) // 注册并使用,路由地址前缀 /api
复制代码

接下来就可以测试下是否成功(Postman,Apipost这两个工具都可以),我们可以看到返回的结果

抽离对应的路由函数事件,在router_handle/user.js文件中创建事件,并在route中引入使用

// router/user.js
const express = require("express")
const route = express.Router()  // 路由的实例化
// 导入抽离路由的事件
const route_handle = require("../router_handle/user")
// 注册用户路由
route.post('/reguser', route_handle.reguser)
// 登录用户路由
route.post('/login', route_handle.login)
// 将挂载好的路由暴露出去
module.exports = route
复制代码
// 注册  router_handle/user.js
exports.reguser = (req, res) => {
    res.send('reguser ok')
}
// login
exports.login = (req, res) => {
    res.send('login ok')
}
复制代码

MySQL

开启数据库(my_db_02),创建表(ev_users)

表创建成功后,我们需要在根目录下创建一个db文件夹来管理数据库,此前我们已经安装过mysql了

// 引入mysql   db/index.js
const mysql = require("mysql")

const db = mysql.createPool({
    host: "127.0.0.1",
    user: 'root', // mysql用户名
    passsword: "123123",// mysql密码
    database: "my_db_02" // 数据库
})

module.exports = db
复制代码

数据库准备完毕后,我们在注册的路由事件中去完成校验匹配(在这里我们需要一个插件bcryptjs npm i bcryptjs进行加密处理)

注册

// 导入数据库 router_handle/user.js
const db = require("../db/index")
// 导入加密处理的插件
const bcryptjs = require("bcryptjs")
// 注册
exports.reguser = (req, res) => {
    const userInfo = req.body  // 获取请求体的内容
    console.log(userInfo, 'userInfo');
    // 定义查询用户名的sql语句
    let sqlStr = 'select * from ev_users where username=?'
    // 使用数据库的查询
    db.query(sqlStr, userInfo.username, (err, results) => {
        // 验证用户名
        if (err) {
            return res.send({ status: 1, message: err.message })
        }
        console.log(results, 'results');
        if (results.length > 0) {
            return res.send({ status: 1, message: "用户名已被注册" })
        }
        // 验证密码 (需要安装插件bcryptjs,npm i bcryptjs)
        // 存进数据库对密码进行了加密处理
        userInfo.password = bcryptjs.hashSync(userInfo.password, 10)
        // 定义插入数据的sql
        let sqlSet = 'insert into ev_users set ?'
        db.query(sqlSet, { username: userInfo.username, password: userInfo.password }, (err, results) => {
            if (err) {
                return res.send({ status: 1, message: err.message })
            }
            if (results.affectedRows !== 1) {
                return res.send({
                    status: 1,
                    message: "注册用户失败,请稍后重试"
                })
            } else {
                res.send({ status: 1, message: "注册成功" })
            }
        })
    })
}

复制代码

验证表单的数据

前端验证为辅,后端验证为主,我们要在后端进行数据的校验尤为重要,在根目录下创建一个文件schema,并安装两个插件( npm i joi @escook/express-joi)

// 导入定义验证规则包 schema/user.js
const joi = require("joi")

// 定义用户名和密码验证规则
const username = joi.string().alphanum().min(1).max(10).required()
const password = joi.string().pattern(/^[\S]{6,12}$/).required()

// 定义验证注册和登录表单的数据规则对象
exports.reg_login_schema = {
    body: {
        username,
        password
    }
}

复制代码

定义好校验后,在router里进行配置

// 导入验证数据的中间件
const expressJoi = require("@escook/express-joi")
// 导入验证的对象
const { reg_login_schema } = require("../schema/user")
// 注册用户路由(路由中间加入校验体)
route.post('/reguser', expressJoi(reg_login_schema), route_handle.reguser)
// 登录用户路由
route.post('/login', expressJoi(reg_login_schema), route_handle.login)
复制代码

然会要在app.js中在路由之后定义错误级别中间件

// 在上边导入joi
const Joi = require("joi")
// 路由之后
app.use((err, req, res, next) => {
    if (err instanceof joi.ValidationError) {
        return res.send({ status: 1, message: err.message })
    }
})
复制代码

登录

登录要验证用户名与密码,登录成功要生成token值,在根目录下新建config.js,生成token的配置文件( npm i jsonwebtoken@8.5.1)

// 导入token包 config.js
const jwt = require("jsonwebtoken")
const config = require("../config")
复制代码
// router_handle/user.js
exports.login = (req, res) => {
    let userInfo = req.body
    let sqlLogin = `select * from ev_users where username=?`
    db.query(sqlLogin, userInfo.username, (err, results) => {
        if (err) {
            return res.send({ststus:1,message:err.message})
        }
        // console.log(results[0], 'results');
        if (results.length !== 1) {
            return res.send({ststus:1,message:'登录失败'})
        }
        // 校验传输密码与数据库密码的正确性 (bcrypt.compareSync (用户输入密码,数据库密码))
        const isPsd = bcryptjs.compareSync(userInfo.password, results[0].password)  
        if (!isPsd) {
            res.send({ststus:1,message:'登录失败'})
        } else {
             // 将密码和头像数据置为空进行token的生成
            const user = { ...results[0], password: "", user_pic: "" }
            // 生成Token
            const token = jwt.sign(user, config.jwtSecretKey, { expiresIn: config.expiresIn })
            res.send({
                status: 0,
                message: "登录成功",
                token: "Bearer " + token
            })
        }
    })
}
复制代码

ok,可以看到登录账号密码123456时,返回成功并带有token值,数据库中没有账号12345,所以登录失败

解析token的中间件

先安装插件 npm i express-jwt@5.3.3

//引入解析token的插件  (app.js)
const expressJWT = require("express-jwt")
const config = require("./config")
复制代码

要在路由之前配置解析token的插件

app.use(expressJWT({ secret: config.jwtSecretKey }).unless({ path: [/^\/api/] })) 在判断错误级别的中间件中进行判断提示

if (err.name === "UnauthorizedError") return res.cc("认证失败")

以下是验证的情况:

1.登录成功时,拿到token

2.去发起一个随意路径(目前路由只有登录和注册两个)的请求,但不是以/api开头的,因为上面我们已经对/api开头的进行了校验,我们可以看到认证失败

3.把登录成功的token值放在header中带进去,我们可以看到请求认证通过,但是返回error,是因为我们没有当前请求路径

在学习中前行,在激流中涌进。学习笔记。


作者:狂徒张三本尊
链接:https://juejin.cn/post/7122704687559606286
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值