首页
友链
导航
影视
壁纸
统计
留言板
Search
1
el-upload自定义触发按钮及触发上传前判断
843 阅读
2
vue配置二级目录以及nginx多网站部署
701 阅读
3
el-cascader选择任意一级搭配懒加载使用,单选框radio不会触发懒加载
578 阅读
4
joe主题自定义导航页面
516 阅读
5
js获取昨天今天明天日期
480 阅读
web前端
vue
react
javascript
nuxt
typescript
indexDB数据库
微信小程序
美文欣赏
心情随笔
技术分享
其他
PHP
nodejs
博客api实战项目
typecho
登录
Search
标签搜索
web
vue
node项目实战
js
javascript
typecho
css
vuex
router
nginx
git
element
joe
utils
leaflet
dateFormat
map
date
axios
reg
辰漪
累计撰写
66
篇文章
累计收到
122
条评论
首页
栏目
web前端
vue
react
javascript
nuxt
typescript
indexDB数据库
微信小程序
美文欣赏
心情随笔
技术分享
其他
PHP
nodejs
博客api实战项目
typecho
页面
友链
导航
影视
壁纸
统计
留言板
搜索到
11
篇与
nodejs
的结果
2022-01-20
10-博客api接口项目实战之接口文档
title: 个人博客 v1.0.0language_tabs:shell: Shellhttp: HTTPjavascript: JavaScriptruby: Rubypython: Pythonphp: PHPjava: Javago: Gotoc_footers: []includes: []search: truehighlight_theme: darkulaheadingLevel: 2个人博客v1.0.0DefaultPOST 登录POST /api/loginBody 请求参数type: object properties: username: type: string description: 用户名 example: admin password: type: string description: 密码 example: "1314521999" required: - username - password 请求参数名称位置类型必选说明bodybodyobjectfalsenone» usernamebodystringtrue用户名» passwordbodystringtrue密码返回示例成功{ "status": 0, "message": "登陆成功!", "userInfo": { "user_id": 15, "username": "admin", "password": "", "nickname": "辰漪", "user_pic": "https://wrz521.top:8080/uploads/art_cover-2021-09-13 16-56-36.png", "is_admin": 1, "is_use": 1, "reg_time": "2021-08-26T08:08:08.000Z" }, "token": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNSwidXNlcm5hbWUiOiJhZG1pbiIsInBhc3N3b3JkIjoiIiwibmlja25hbWUiOiLovrDmvKoiLCJ1c2VyX3BpYyI6Imh0dHBzOi8vd3J6NTIxLnRvcDo4MDgwL3VwbG9hZHMvYXJ0X2NvdmVyLTIwMjEtMDktMTMgMTYtNTYtMzYucG5nIiwiaXNfYWRtaW4iOjEsImlzX3VzZSI6MSwicmVnX3RpbWUiOiIyMDIxLTA4LTI2VDA4OjA4OjA4LjAwMFoiLCJpYXQiOjE2NDAxNDk4MjcsImV4cCI6MTY0MDE4NTgyN30.bXcGc-iMvVhICfF64EWpBZcQxETbkCFqWORnRgiCnCg" }返回结果状态码状态码含义说明数据模型200OK成功Inline返回数据结构状态码 200名称类型必选约束说明» statusintegertruenone是否成功 0 成功 1 失败» messagestringtruenone说明信息» userInfoobjecttruenone用户信息»» user_idintegertruenone用户id»» usernamestringtruenone用户名»» passwordstringtruenone密码»» nicknamestringtruenone昵称»» user_picstringtruenone用户头像»» is_adminintegertruenone是否管理员»» is_useintegertruenone能否使用»» reg_timestringtruenone注册时间» tokenstringtruenonetokenblogGET 获取用户信息列表分页GET /my/getUserListPage请求参数名称位置类型必选说明fuzzyquerystringfalse查询字符串(通过username 或者 nickname)可以传空 获取全部pageNumquerystringfalse当前页码(默认 1)pageSizequerystringfalse每页显示条数(默认 10)sortKeyquerystringfalse根据哪个字段排序sortValuequerystringfalsedesc降序 asc升序Authorizationheaderstringtruenone返回示例成功{ "status": 0, "msg": "获取用户列表成功!", "total": 6, "data": [ { "user_id": 44, "username": "admin3", "nickname": "辰漪3", "user_pic": "3", "is_admin": 0, "is_use": 1, "reg_time": "2022-01-13T05:44:04.000Z" }, { "user_id": 43, "username": "admin2", "nickname": "辰漪1", "user_pic": "1", "is_admin": 0, "is_use": 1, "reg_time": "2022-01-12T06:22:14.000Z" }, { "user_id": 39, "username": "admin11561", "nickname": null, "user_pic": null, "is_admin": 0, "is_use": 1, "reg_time": "2022-01-11T07:25:21.000Z" }, { "user_id": 30, "username": "admin1", "nickname": null, "user_pic": null, "is_admin": 0, "is_use": 1, "reg_time": "2022-01-11T06:44:05.000Z" }, { "user_id": 26, "username": "admin", "nickname": null, "user_pic": null, "is_admin": 0, "is_use": 1, "reg_time": "2022-01-11T06:35:04.000Z" }, { "user_id": 16, "username": "123", "nickname": null, "user_pic": null, "is_admin": 0, "is_use": 1, "reg_time": "2022-01-11T06:06:24.000Z" } ] }返回结果状态码状态码含义说明数据模型200OK成功Inline返回数据结构状态码 200名称类型必选约束说明» statusintegertruenonenone» msgstringtruenonenone» totalintegertruenonenone» data[object]truenonenone»» user_idintegertruenonenone»» usernamestringtruenonenone»» nicknamestring¦nulltruenonenone»» user_picstring¦nulltruenonenone»» is_adminintegertruenonenone»» is_useintegertruenonenone»» reg_timestringtruenonenonePOST 用户注册POST /api/reguserBody 请求参数type: object properties: username: type: string description: 用户名 password: type: string description: 密码 required: - username - password 请求参数名称位置类型必选说明bodybodyobjectfalsenone» usernamebodystringtrue用户名» passwordbodystringtrue密码返回示例成功{ "status": 0, "msg": "注册成功!" }返回结果状态码状态码含义说明数据模型200OK成功Inline返回数据结构状态码 200名称类型必选约束说明» statusintegertruenonenone» msgstringtruenonenonePOST 文件上传POST /my/uploadsBody 请求参数type: object properties: avatar: type: string description: 要上传的文件信息 format: binary 请求参数名称位置类型必选说明Authorizationheaderstringtrue身份认证bodybodyobjectfalsenone» avatarbodystring(binary)false要上传的文件信息返回示例成功{ "status": 0, "fileInfo": { "fieldname": "avatar", "originalname": "g.png", "encoding": "7bit", "mimetype": "image/png", "destination": "./uploads", "filename": "avatar-2022-01-20 14-43-33.png", "path": "/uploads/avatar-2022-01-20 14-43-33.png", "size": 19531 }, "msg": "上传成功!" }返回结果状态码状态码含义说明数据模型200OK成功Inline返回数据结构状态码 200名称类型必选约束说明» statusintegertruenonenone» fileInfoobjecttruenonenone»» fieldnamestringtruenonenone»» originalnamestringtruenonenone»» encodingstringtruenonenone»» mimetypestringtruenonenone»» destinationstringtruenonenone»» filenamestringtruenonenone»» pathstringtruenonenone»» sizeintegertruenonenone» msgstringtruenonenonePUT 更新用户基本资料PUT /my/updateInfoBody 请求参数type: object properties: nickname: type: string description: 昵称 user_pic: type: string description: 头像 is_admin: type: string description: 是否管理员 is_use: type: string description: 账号是否可用 请求参数名称位置类型必选说明user_idquerystringtrue用户idAuthorizationheaderstringtruetokenbodybodyobjectfalsenone» nicknamebodystringfalse昵称» user_picbodystringfalse头像» is_adminbodystringfalse是否管理员» is_usebodystringfalse账号是否可用返回示例成功{ "status": 0, "msg": "修改成功!" }返回结果状态码状态码含义说明数据模型200OK成功Inline返回数据结构状态码 200名称类型必选约束说明» statusintegertruenonenone» msgstringtruenonenonePUT 修改密码PUT /my/updatePwdBody 请求参数type: object properties: currentPwd: type: string description: 当前密码 editPwd: type: string description: 要修改的密码 repeatPwd: type: string description: 重复密码 required: - currentPwd - editPwd - repeatPwd 请求参数名称位置类型必选说明user_idquerystringtrue用户idAuthorizationheaderstringtruetokenbodybodyobjectfalsenone» currentPwdbodystringtrue当前密码» editPwdbodystringtrue要修改的密码» repeatPwdbodystringtrue重复密码返回示例返回结果状态码状态码含义说明数据模型200OK失败Inline返回数据结构状态码 200名称类型必选约束说明» statusintegertruenonenone» msgstringtruenonenone数据模型
2022年01月20日
95 阅读
4 评论
1 点赞
2022-01-20
09-博客api接口项目实战之自动化导入路由
使用自动化导入路由使用自动化导入路由文件,就不需要自己一个一个导入了更改路由文件命名格式,以api开头 或者 以 my开头,用于判断是否需要token认证比如 router/user.js 改成 apiUser.js文件 upload.js 改成 myUpload.js封装自动化导入函数其实就是用到node的fs模块,使用fs.readdirSync()方法获取目录下的所有文件名称组成的数组,拼接路径,然后使用require()导入,再使用app.use()进行路由注册// utils/createRouter.js const fs = require('fs') /** * 挂载路由函数 * @param {object} app serve实例 * @param {string} path 路由文件所在目录绝对路径 * @param {string} dir 路由文件所在目录 */ const cerateRouter = (app, path, dir) => { const routerDir = fs.readdirSync(dir) // 所有的路由文件名称组成的数组 routerDir.forEach(item => { const url = path + '\\' + item const router = require(url) item.startsWith('api') ? app.use('/api', router) : app.use('/my', router) }) } module.exports = cerateRouter 如何使用?在app.js中 导入函数并执行const createRouter = require('./utils/createRouter') // 挂载路由函数 // __dirname是一个node变量,表示当前执行文件所在目录 createRouter(app, __dirname + '\\router', 'router') // 调用,并传参
2022年01月20日
32 阅读
0 评论
0 点赞
2022-01-20
08-博客api接口项目实战之文件上传
实现上传文件功能需要字段 avatar 为文件信息对象限定,只能上传 jpg jpeg png gif 格式的图片有必要的话可以设置下文件上传的文件大小需要用到的npm包:multer 用来上传文件multer官网文档:https://github.com/expressjs/multer/blob/master/doc/README-zh-cn.md实现步骤1. 安装multer包npm install multer2. 创建路由在router下新建upload.js文件const { Router } = require('express') const router = Router() const dateFormat = require('../utils/dateFormat') const uploadHandler = require('../router_handler/upload') const multer = require('multer') // 上传文件所需要的包 // 设置文件存储的格式,以及位置 const storage = multer.diskStorage({ destination: function (req, file, cb) { // 设置文件存储的位置 cb(null, './uploads') }, filename: function (req, file, cb) { // 设置文件名的格式 // 获取文件后缀名 const prefix = file.originalname.split('.')[file.originalname.split('.').length - 1] cb(null, file.fieldname + '-' + dateFormat(new Date(), 'yyyy-MM-dd hh-mm-ss') + '.' + prefix) } }) // 设置文件过滤器 用来过滤不符合条件的文件 const fileFilter = (req, file, cb) => { // 设置文件格式 const type = ['image/png', 'image/jpeg', 'image/jpg', 'image/gif'] if (type.includes(file.mimetype)) return cb(null, true) cb(new Error('上传失败,不支持的文件格式'+file.mimetype), false) } const upload = multer({ storage, fileFilter, }) // 上传文件 router.post('/uploads', upload.single('avatar'), uploadHandler) module.exports = router 3. 创建路由处理函数在router_handler下创建upload.js // 上传文件 const uploadHandler = (req, res) => { if (!req.file) return res.cc('field:avatar is file and required!') const fileInfo = req.file fileInfo.path = `/uploads/${fileInfo.filename}` res.send({ status: 0, fileInfo, msg: '上传成功!' }) } module.exports = uploadHandler4. 测试接口: http://127.0.0.1:8086/my/uploads请求路径:/my/uploads请求方法:post请求头:Authorization: 登录token请求参数:请求参数参数类型参数说明备注avatarfile文件对象信息必填
2022年01月20日
33 阅读
0 评论
0 点赞
2022-01-20
07-博客api接口项目实战之获取用户列表
实现用户列表获取功能接口所需字段:fuzzy 查询字符串 pageNum 页码 pageSize 每页显示条数查询字符串查的是username用户名和nickname昵称,允许为空页码默认为1,不允许传空,非必填每页条数默认为10,不允许传空,非必填实现步骤1. 创建字段校验对象// schema/user.js // 获取用户列表 const getUser = { query: { fuzzy: joi.string().allow(''), pageNum: joi.number().integer().min(1).disallow(''), pageSize: joi.number().integer().min(1).disallow(''), sortKey: joi.string().disallow(''), sortValue: joi.string().disallow('') } } module.exports = { reg_login, updatePwd, updateInfo, getUser }2. 封装自定义sql执行函数// utils/db.js /** * 通过sql语句查询 * @param {String} sql sql语句 **/ const selectDataBySql = function (sql) { return new Promise((resolve, reject) => { db.query(sql, (err, res) => { if (err) { resolve({status: 1, msg: 'sql语句查询失败', data: null, err}) } else { resolve({status: 0, msg: 'sql语句查询成功', data: res, err: null}) } }) }) } module.exports = { addData, updateData, selectData, selectDataBySql // 向外共享sql语句查询函数 }3. 创建路由// router/userInfo.js const { updatePwd, updateInfo, getUserList } = require('../router_handler/userinfo') // 获取用户列表 router.get('/getUserListPage', validateJoi(userSchema.getUser), getUserList)4. 创建路由处理函数如果传了pageNum 就用 pageNum 否则默认1如果传了pageSize 就用pageSize 否则默认10fuzzy 不传或空 查询所有用户列表,传了查询username或者nickname为fuzzy的用户列表sortKey排序字段,不传不排序sortValue排序规则,升序还是降序// router_handler/userInfo.js // 获取用户列表 const getUserList = async (req, res) => { let {fuzzy, pageNum, pageSize, sortKey, sortValue} = req.query if (!pageNum) pageNum = 1 if (!pageSize) pageSize = 10 let totalSql = `select count(*) AS total from users` // 查询所有数据总条数 let selectSql = `select user_id,username,nickname,user_pic,is_admin,is_use,reg_time from users` // 查询表数据 let total = 0 // 总条数 if (fuzzy) { // 查询用户名或昵称为fuzzy的用户列表 totalSql += ` where username like '%${fuzzy}%' or nickname like '%${fuzzy}%'` selectSql += ` where username like '%${fuzzy}%' or nickname like '%${fuzzy}%'` } // 添加分页和排序 根据注册时间 添加limit分页 if (sortKey && sortValue) selectSql += ` order by ${sortKey} ${sortValue} limit ${(pageNum - 1) * pageSize},${pageSize}` selectSql += ` limit ${(pageNum - 1) * pageSize},${pageSize}` // 不排序 // 执行sql语句 const totalRes = await db.selectDataBySql(totalSql) if (totalRes.status !== 0) return res.cc(totalRes.err) total = totalRes.data[0].total // 总条数 const sqlectRes = await db.selectDataBySql(selectSql) if (sqlectRes.status !== 0) return res.cc(sqlectRes.err) const userList = sqlectRes.data res.send({ status: 0, msg: '获取用户列表成功!', total, data: userList }) } module.exports = { updatePwd, updateInfo, getUserList }5. 测试接口:http://127.0.0.1:8086/my/getUserListPage请求路径:/my/updateInfo请求方法:get请求头:Authorization: 登录token请求参数:请求参数参数类型参数说明备注fuzzyString查询字符串非必填 允许为空pageNumNumber页码非必填 非空 默认 1pageSizeNumber每页显示条数非必填 非空 默认 10sortKeyString排序字段非必填 非空sortValueString排序值非必填 非空 (desc 降序、asc升序)
2022年01月20日
33 阅读
0 评论
0 点赞
2022-01-20
06-博客api接口项目实战之数据库方法封装
使用promise封装数据库操作方法在utils文件夹中创建db.js1. 根据字段查询数据// db.js /** * 根据某个字段查询数据 * @param {String} storeName 表名 * @param {String} key 字段 * @param {String} value 字段值 **/ const selectData = function (storeName, key, value) { return new Promise((resolve, reject) => { const sql = `select * from ${storeName} where ${key} = ${value}` console.log(sql); db.query(sql, (err, res) => { if (err) { resolve({status: 1, msg: '查询失败', data: null, err}) } else { resolve({status: 0, msg: '查询成功', data: res, err: null}) } }) }) }2. 根据字段更新数据// db.js /** * 根据某个字段更新数据 * @param {String} storeName 表名 * @param {Object} data 要更新的数据 * @param {String} key 字段 * @param {String} value 字段值 **/ const updateData = function (storeName, data, key, value) { return new Promise((resolve, reject) => { const sql = `update ${storeName} set ? where ${key} = ${value}` db.query(sql, data, (err, res) => { if (err) { resolve({status: 1, msg: '更新数据失败', data: null, err}) } else { resolve({status: 0, msg: '更新数据成功', data: res, err: null}) } }) }) }3. 给某个表中添加数据// db.js /** * 添加数据 * @param {String} storeName 表名 * @param {Object} data 要插入的数据 * @param **/ const addData = function (storeName, data) { return new Promise((resolve, reject) => { const sql = `insert into ${storeName} set ?` db.query(sql, data, (err, res) => { if (err) { resolve({status: 1, msg: '插入数据失败', data: null, err}) } else { resolve({status: 0, msg: '插入数据成功', data: res, err: null}) } }) }) }我在这里都用的是resolve,你也可以用reject,reject抛出,需要使用.catch捕获使用实例:修改用户基本信息处理函数 router_handler/userInfo.js// 更新用户基本资料 const updateInfo = async (req, res) => { const user_id = req.query.user_id const userInfo = req.body if (JSON.stringify(userInfo) === '{}') return res.cc('请填写要修改的参数!') // 查询 const selectData = await db.selectData('users', 'user_id', user_id) if (selectData.status !== 0) return res.cc(selectData.err) if (selectData.data.length !== 1) return res.cc('该用户不存在!') // 更新 const updateData = await db.updateData('users', userInfo, 'user_id', user_id) if (updateData.status !== 0) return res.cc(updateData.err) const {data: result} = updateData if (result.affectedRows !== 1) return res.cc('更新用户信息失败,请重试!') res.send({ status: 0, msg: '修改成功!' }) }其他路由处理函数,自己看着调整,后续就直接使用promise操作数据库,根据实际情况封装对应的数据库操作方法
2022年01月20日
35 阅读
0 评论
0 点赞
2022-01-20
05-博客api接口项目实战之基本信息修改
实现用户基本信息修改功能允许修改 昵称(nickname) 头像(user_pic) 是否管理员(is_admin) 账号是否可用(is_use),需要进行token认证实现步骤:1. 创建字段校验对象// schema/user.js // 修改用户基本信息 const updateInfo = { query: { user_id }, body: { nickname: joi.string().max(10).disallow(''), user_pic: joi.string().allow(''), is_admin: joi.number().integer().valid(0, 1), is_use: joi.number().integer().valid(0, 1) } } module.exports = { reg_login, updatePwd, updateInfo }2. 创建路由// router/userInfo.js const { updatePwd, updateInfo } = require('../router_handler/userinfo') // 更新基本用户信息 router.put('/updateInfo', validateJoi(userSchema.updateInfo), updateInfo)3. 创建路由处理函数检查数据库是否有该用户拿到更新的参数数据,更新该用户的数据库信息// router_handler/userInfo.js // 更新用户基本资料 const updateInfo = (req, res) => { const user_id = req.query.user_id const userInfo = req.body // console.log(req.user); if (JSON.stringify(userInfo) === '{}') return res.cc('请填写要修改的参数!') const sql = `select * from users where user_id = ?` const sql2 = `update users set ? where user_id = ?` db.query(sql, user_id, (err, result) => { if (err) return res.cc(err) if (result.length !== 1) return res.cc('用户不存在!') db.query(sql2, [userInfo, user_id], (err, result) => { if (err) { const arr = err.sqlMessage.split(' ') if (err.code === 'ER_DUP_ENTRY' && arr[arr.length -1] === "'nickname'") return res.cc('昵称重复,换一个叭!') return res.cc(err) } if (result.affectedRows !== 1) return res.cc('更新用户信息失败,请重试!') res.send({ status: 0, msg: '修改成功' }) }) }) } module.exports = { updatePwd, updateInfo }4. 测试接口:http://127.0.0.1:8086/my/updateInfo请求路径:/my/updateInfo请求方法:put请求头:Authorization: 登录token请求参数:请求参数参数类型参数说明备注user_idNumber用户id以query参数携带必填nicknameString用户昵称非必填 非空 10位user_picString用户头像非必填 允许为空is_adminNumber是否管理员非必填 只能是0 或 1is_useNumber账号是否可用非必填 只能是0 或 1
2022年01月20日
23 阅读
0 评论
0 点赞
2022-01-20
04-博客api接口项目实战之密码修改
实现密码修改功能在router下新建userinfo.js存放用户信息相关的路由在router_handler下新建userinfo.js存放用户信息相关的路由处理函数密码修改需要进行token认证,需要在请求头携带Authorization字段app.js中在所有路由之前,使用express-jwt中间件解析token1. app.js中添加token解析中间件,在错误级别中间件中添加token解析报错处理... // 在路由之前解析token 排除 api和uploads开头的路由 const expressJWT = require('express-jwt') // 解析token const { jwtConfig } = require('./config') // token配置 记录了 秘钥 有效期 app.use(expressJWT({ secret: jwtConfig.jwtKey, algorithms: ['HS256'] }).unless({ path: [/^\/api/, /^\/uploads/] })) // 托管静态资源 以后上传文件要用 app.use('/uploads', express.static('./uploads')) // 定义错误级别中间件 app.use((err, req, res, next) => { // 字段校验错误捕获 if (err instanceof joi.ValidationError) return res.cc(err) // 捕获身份认证错误 if (err.name === 'UnauthorizedError') { if (err.message === 'jwt expired') return res.cc('token过期,请重新登录!', 401) return res.cc('身份认证失败!', 401) } // 其他错误 res.cc(err) }) ...2. 创建路由// router/userinfo.js const { Router } = require('express') const router = Router() const validateJoi = require('../utils/validate') // 校验数据 const userSchema = require('../schema/user') const { updatePwd } = require('../router_handler/userinfo') // 修改密码 router.put('/updatePwd', validateJoi(userSchema.updatePwd), updatePwd) module.exports = router3. 创建路由处理函数检查数据库中是否有这个人校验当前密码是否正确校验要修改的密码和重复的密码是否相同校验要修改的密码是否和原先密码一致全部通过执行更新密码// router_handler/userinfo.js const bcrypt = require('bcryptjs') // 密码加密和解密 const db = require('../db/index') // 导入数据库对象 // 修改密码 const updatePwd = (req, res) => { const user_id = req.query.user_id const { currentPwd, editPwd, repeatPwd } = req.body const sql = `select * from users where user_id = ?` db.query(sql, user_id, (err, result) => { if (err) return res.cc(err) if (result.length !== 1) return res.cc('用户不存在!') console.log(currentPwd); const compareResult = bcrypt.compareSync(currentPwd, result[0].password) if (!compareResult) return res.cc('当前密码错误!') if (currentPwd === editPwd) return res.cc('不能与原先密码一致!') const sql1 = `update users set ? where user_id = '${user_id}'` const password = bcrypt.hashSync(repeatPwd, 10) db.query(sql1, {password: password}, (err, result) => { if (err) return res.cc(err) if (result.affectedRows !== 1) return res.cc('修改失败,请重试!') res.send({ status: 0, msg: '修改成功!' }) }) }) }4. 测试密码修改接口:http://127.0.0.1:8086/my/updatePwd请求路径:/my/updatePwd请求方法:put请求头:Authorization: 登录token请求参数:请求参数参数类型参数说明备注user_idNumber用户id以query参数携带currentPwdString当前密码 editPwdString要修改的密码 repeatPwdString重复修改的密码
2022年01月20日
21 阅读
0 评论
0 点赞
2022-01-20
03-博客api接口项目实战之用户登录
1. 实现登录功能所需字段:username password所需npm包:jsonwebtoken 生成token express-jwt 解析tokennpm install jsonwebtoken express-jwtexpress-jwt官方文档:https://www.npmjs.com/package/express-jwtjsonwebtoken官方文档:https://www.npmjs.com/package/jsonwebtoken实现步骤定义登录字段校验规则对象// schema/user.js const joi = require('joi') const reg_login = { body: { username: joi.string().alphanum().min(1).max(10).required(), password: joi.string().pattern(/^[\S]{6,12}$/).required() } } module.exports = { reg_login }登录和注册实际上都是校验username 和 password,可以共用,注意修改 用户注册路由验证// 用户注册 router.post('/reguser', validateJoi(userSchema.reg_login), user_handler.regUser)创建路由// router/user.js // 添加登录路由 // 用户登录 router.post('/login', validateJoi(userSchema.reg_login), user_handler.login)创建路由处理函数登录实现:拿到用户名查询数据库有没有此人,没有,返回查无此人,有则继续下一步拿到当前用户在数据库的密码,使用bcrypt和当前输入的密码进行对比,密码错误,返回密码错误,登陆失败,否则进行下一步使用jsonwebtoken创建token,返回登陆成功以及token,再加上用户的基本信息// router_handler/user.js // 登录 const login = (req, res) => { const userInfo = req.body const sql = `select * from users where username = ?` // 查询用户在不在数据库中 db.query(sql, userInfo.username, (err, result) => { if (err) return res.cc(err) if (result.length !== 1) return res.cc('登陆失败,查无此人!') // TODO:判断用户输入的登录密码是否和数据库中的密码一致 const compareResult = bcrypt.compareSync(userInfo.password, result[0].password) if (!compareResult) return res.cc('密码错误,登录失败!') const user = { ...result[0], password: '' } // 将查询到的用户信息的密码剔除 // 创建token jwt.sign(加密信息, 加密秘钥, 有效期) const token = jwt.sign(user, 'cjaliwbfsia1sa', {expiresIn: '24h'}) res.send({ status: 0, msg: '登陆成功!', userInfo: user, token: 'Bearer ' + token }) }) }可以将jwt加密秘钥和有效期抽离成一个文件 config.js,在根目录创建// config.js const jwtConfig = { jwtKey: 'cjaliwbfsia1sa', // jwt秘钥 expiresIn: '24h' // token有效期 } module.exports = { jwtConfig }哪里要用就引入// 修改 登录路由 const { jwtConfig } = require('../config') const token = jwt.sign(user, jwtConfig.jwtKey, {expiresIn: jwtConfig.expiresIn})测试登录接口: http://127.0.0.1:8086/api/login请求路径:/api/login请求方法:post请求参数:请求参数参数类型参数说明备注usernameString用户名不能为空 长度1-10位passwordString密码不能为空 长度6-12位
2022年01月20日
28 阅读
0 评论
0 点赞
2022-01-20
02-博客api接口项目实战之用户注册
1. 安装数据库及可视化数据库管理工具(navicat)数据库管理工具(Navicat 15)安装激活教程2. 创建数据库及表创建一个名为blog的数据库双击打开blog数据库,右键表,新建表,创建一个名为users的数据表3. 实现注册功能注册功能其实就是给users表中插入数据注册所需字段:username password所需npm包: bcryptjs 用来给密码进行加密 mysql 用来连接数据库,操作数据库 joi 用来数据校验 body-parser 用来提交表单数据,处理表单数据,处理完之后挂载到req.body上npm install bcryptjs mysql joi body-parser3.1 实现步骤3.1.1. 数据库连接在db文件夹下创建文件index.js// db/index.js const mysql = require('mysql') const db = mysql.createConnection({ // 连接数据库 host: '127.0.0.1', // 127.0.0.1 / localhost user: 'root', // 数据库用户名 password: '123456', // 密码 database: 'blog' // 数据库名称 }) module.exports = db操作数据库通过 db.query()方法mysql详细api文档:https://www.npmjs.com/package/mysql3.1.2. 创建用户注册字段校验函数和时间格式化函数joi详细api文档:https://joi.dev/api/?v=17.5.0在utils中创建validate.js用来校验字段,当做中间件使用// 校验数据 // schemas 校验对象 const joi = require('joi') const validateJoi = function (schemas) { // TODO: 用户指定了什么 schema,就应该校验什么样的数据 return function (req, res, next) { ;['query', 'body', 'params'].forEach((key) => { // 如果当前循环的这一项 schema 没有提供,则不执行对应的校验 if (!schemas[key]) return // 执行校验 const schema = joi.object(schemas[key]) const { error, value } = schema.validate(req[key]) if (error) { // 校验失败 throw error } else { // 校验成功,把校验的结果重新赋值到 req 对应的 key 上 req[key] = value } }) // 校验通过 next() } } module.exports = validateJoi 在utils中添加时间格式化函数/* *@params date {Date Object} 日期 *@params fmt {String} 格式化方式 *@params bool {Boolean} 是否返回周几 */ function dateFormat(date, fmt, bool) { date = new Date(date) var o = { "M+": date.getMonth() + 1, //月份 "d+": date.getDate(), //日 "h+": date.getHours(), //小时 "m+": date.getMinutes(), //分 "s+": date.getSeconds(), //秒 "q+": Math.floor((date.getMonth() + 3) / 3), //季度 S: date.getMilliseconds(), //毫秒 } let weekStr = "" // 星期几 const weekList = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'] weekStr = weekList[date.getDay()] if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length)) } for (var k in o) { if (new RegExp("(" + k + ")").test(fmt)) { fmt = fmt.replace( RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length) ) } } if (bool) fmt = fmt + " " + weekStr return fmt } module.exports = dateFormat // console.log(dateFormat(+new Date(), "yyyy-MM-dd hh:mm:ss", 1)) 在schema文件夹下创建user.js存放用户相关的字段校验对象// schema/user.js // 用户相关的字段校验 const joi = require('joi') // username password const reg = { body: { // 只能包含字母数字最小为1最大为10的字符串,并且必填 username: joi.string().alphanum().min(1).max(10).required(), // 符合正则的字符串,并且必填 password: joi.string().pattern(/^[\S]{6,12}$/).required() } } module.exports = { reg }3.1.3. 在router文件夹下创建文件 user.js 专门存放用户相关的路由// router/user.js // 用户相关的路由 const { Router } = require('express') const router = Router() const validateJoi = require('../utils/validate') // 校验数据 // 路由处理函数 const user_handler = require('../router_handler/user') const userSchema = require('../schema/user') // 用户相关的校验对象 // 用户注册 router.post('/reguser', validateJoi(userSchema.reg), user_handler.regUser)3.1.4. 在router_handler文件夹下创建文件 user.js 专门存放用户相关的路由处理函数// touter_handler/user.js const bcrypt = require('bcryptjs') // 密码加密和解密 const db = require('../db/index') // 导入数据库对象 const dateFormat = require('../utils/dateFormat') // 时间格式化 // 注册 const regUser = (req, res) => { // 用户名密码校验正确 const userInfo = req.body const sql = `insert into users set ?` userInfo.reg_time = dateFormat(new Date(), 'yyyy-MM-dd hh:mm:ss') userInfo.password = bcrypt.hashSync(userInfo.password, 10) // 对密码加密 db.query(sql, userInfo, (err, result) => { if (err && err.code === 'ER_DUP_ENTRY') { const arr = err.sqlMessage.split(' ') return arr[arr.length - 1] === "'username'" ? res.cc('用户名重复,换一个叭!') : res.cc(err.sqlMessage) } if (result.affectedRows !== 1) return res.cc('注册失败,请稍后重试!') res.cc('注册成功!', 0) }) } module.exports = { regUser } 3.1.5 在app.js中挂载路由,添加错误级别中间件,以及错误输出状态函数... const joi = require('joi') const bodyParser = require('body-parser') const userRouter = require('./router/user') // 用户相关的路由 // 定义输出错误状态的中间件 app.use((req, res, next) => { // 挂载函数,全局能用 res.cc = function (err, status = 1) { res.send({ status, msg: err instanceof Error ? err.message : err }) } next() }) // 处理表单数据 app.use(bodyParser.urlencoded({ extended: false })) app.use(bodyParser.json()) app.use('/api', userRouter) // 定义错误级别中间件 放在所有路由后边 app.use((err, req, res, next) => { // joi校验错误 if (err instanceof joi.ValidationError) return res.cc(err) }) ...3.1.6 测试注册接口: http://127.0.0.1:8086/api/reguser请求路径:/api/reguser请求方法:post请求参数:请求参数参数类型参数说明备注usernameString用户名不能为空 长度1-10位passwordString密码不能为空 长度6-12位
2022年01月20日
37 阅读
0 评论
0 点赞
2022-01-20
01-博客api接口项目实战之服务器创建
1. 新建一个server文件夹2. 创建项目的基本结构db 存放数据库文件router 存放路由文件router_handler 存放路由处理函数文件schema 路由字段验证文件uploads 文件上传的静态资源文件utils 工具函数app.js 服务器运行文件3. 创建包管理文件后续可能会用到很多npm包在server文件夹内打开cmd 或 powerShellnpm init -y会自动生成一个package.json包管理配置文件。创建4. 创建git仓库,并提交使用gitee码云:https://gitee.com/先创建一个仓库 server仓库地址: https://gitee.com/wrz666/server.git 换成自己的创建.gitignore忽略文件,避免上传不必要的文件,忽略uploads文件夹.DS_Store node_modules /dist /uploads # local env files .env.local .env.*.local # Log files npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* # Editor directories and files .idea .vscode *.suo *.ntvs* *.njsproj *.sln *.sw?在server文件夹内打开cmd 或 powerShellgit init // 初始化git git add . // 添加到暂存区 git commit -m '项目初始化' // 提交到本地仓库 git remote add origin https://gitee.com/wrz666/server.git // 和git仓库绑定 git push -u origin "master" // 推送到远程master分支git默认不会上传空的文件夹,所以只有两个文件5. 使用express创建服务器5.1. 下载express包npm install express5.2. app.js中使用express创建服务器// app.js const express = require('express') const res = require('express/lib/response') const app = express() const serve = '' // 后续配置https时用 // get 请求 请求路径为 http://127.0.0.1:8086/ app.get('/', (req, res) => { res.send(`<h1>标题</h1>`) // 向客户端发送一个html标签 也可以发送一个字符串,json对象 }) let port = 8086 // 端口 let protocol = serve ? 'https' : 'http' // 协议 app.listen(port, () => { console.log(`serve is running at ${protocol}//127.0.0.1:${port}`) })5.3. 使用node运行app.js文件node /app.js当出现serve is running at http://127.0.0.1:8086,此时服务器就跑起来了5.4. 使用nodemon运行app.js修改之后文件内容之后会自动重新运行全局安装 nodemonnpm install nodemon -g5.5. 测试 http://127.0.0.1:8086/当出现该页面则get请求成功此时路由在一个文件,当路由多了便不好维护,所以将路由拆分为两个文件 一个是路由,一个是路由处理函数,这样方便维护分别放在router 和 router_handler文件夹中
2022年01月20日
85 阅读
3 评论
0 点赞
1
2