創(chuàng)建NodeAPI接口
1、新建文件夾app_server吗伤,在根目錄中打開(kāi)終端輸入:npm i ,生成pack.json文件硫眨;
2足淆、下載express,終端輸入:npm i express@4.17.1(指定版本);
一礁阁、創(chuàng)建服務(wù)器app.js;
// 導(dǎo)入 express 模塊
const express = require('express')
// 創(chuàng)建服務(wù)器的實(shí)例
const app = express()
// 啟動(dòng)服務(wù)器
app.listen(3007,(req, res) => {
console.log('api server running at http://127.0.0.1:3007');
})
4巧号、配置cors跨域
①、在根目錄下執(zhí)行命令按
照:npm i cors@2.8.5;
②姥闭、導(dǎo)入模塊配置解析表單的中間件丹鸿;
// 導(dǎo)入cors并配置cros中間件
const cors = require('cors')
app.use(cors())
// 配置解析application x-www-form-urlencoded 模式的表單數(shù)據(jù) 的中間件
app.use(express.urlencoded({ extended: false}))
二、創(chuàng)建路由
1泣栈、在根目錄下新建router文件夾,用來(lái)存放路由模塊弥姻;新建router_hander文件夾存放路由處理函數(shù)模塊南片;
2、創(chuàng)建路由user.js庭敦;
// 導(dǎo)入 express 模塊
const express = require('express')
// 創(chuàng)建路由對(duì)象
const userRouter = express.Router()
// 掛載路由 注冊(cè)新用戶(hù)
userRouter.post('/reguser', (req, res) => {
res.send('reguser ok')
})
// 掛載路由 登陸
userRouter.post('/login',(req, res) => {
res.send('login ok')
})
// 共享出去router模塊
module.exports = userRouter
3疼进、在服務(wù)器中導(dǎo)入并注冊(cè)路由模塊
// 導(dǎo)入并注冊(cè)路由模塊
const userRouter = require('./router/user')
app.use('/api',userRouter)
4、抽離用戶(hù)路由模塊的處理函數(shù)秧廉,在router_hander文件夾中新建user.js伞广,存放路由模塊的處理函數(shù);
// 注冊(cè)新用戶(hù)的處理函數(shù)
exports.regUser = (req, res) => {
res.send('reguser ok')
}
// 登陸的處理函數(shù)
exports.login = (req, res) => {
res.send('login ok')
}
在路由模塊router文件夾下的user.js疼电,導(dǎo)入router_hander/user.js嚼锄,使用里面共享出來(lái)的模塊;
// 導(dǎo)入用戶(hù)路由處理函數(shù)模塊
const user_hander = require('../router_hander/user')
// 掛載路由 注冊(cè)新用戶(hù)
userRouter.post('/reguser', user_hander.regUser)
// 掛載路由 登陸
userRouter.post('/login',user_hander.login)
5蔽豺、注冊(cè)新用戶(hù)——?jiǎng)?chuàng)建數(shù)據(jù)庫(kù)表格
6区丑、注冊(cè)新用戶(hù)——按照與配置mysql模塊;
在根目錄下打開(kāi)終端輸入:npm i mysql@2.18.1;
在文件夾db下的index.js中導(dǎo)入mysql模塊并創(chuàng)建數(shù)據(jù)庫(kù)連接對(duì)象;
// 導(dǎo)入mysql模塊
const mysql = require('mysql')
// 創(chuàng)建數(shù)據(jù)庫(kù)連接對(duì)象
const db = mysql.createPool({
host: '127.0.0.1',
user: 'root',
password: 'hoshi1234',
datebase: 'my_dv_01'
})
// 向外共享 數(shù)據(jù)庫(kù)的連接對(duì)象
module.exports = db
7沧侥、注冊(cè)新用戶(hù)——檢測(cè)用戶(hù)名是否合法/用戶(hù)名是否被占用/使用bcryptjs給用戶(hù)密碼加密/封裝res.cc()函數(shù)可霎;
在router_hander中的user.js的注冊(cè)新用戶(hù)函數(shù)中,判斷req.body的屬性是否為false宴杀;
導(dǎo)入db數(shù)據(jù)庫(kù)操作模塊癣朗,定義SQL語(yǔ)句查詢(xún)username,當(dāng)它length大于0則代表被占用旺罢;
——————————————
在app.js中旷余,封裝res.cc()函數(shù)作為全局中間件,用來(lái)調(diào)用res.send()函數(shù)像客戶(hù)端處理失敗的結(jié)果
// 優(yōu)化res.send()代碼
// 在處理函數(shù)中需要多次調(diào)用res.send()向客戶(hù)端響應(yīng)處理失敗的結(jié)果主经,為了簡(jiǎn)化代碼可以手動(dòng)分裝一個(gè)res.cc()函數(shù)
// 在路由之前荣暮,聲明一個(gè)全局中間件,為res對(duì)象掛載一個(gè)res.cc()函數(shù)
app.use(function(req, res, next){
res.cc = function(err, status = 1) {
res.send({
status,
// 判斷err是否為錯(cuò)誤對(duì)象(構(gòu)造函數(shù)中的實(shí)例對(duì)象) true 則返回err.message罩驻,false則說(shuō)明它是個(gè)字符串穗酥,直接返回err
message: err instanceof Error ? err.message: err,
})
}
next()
})
優(yōu)化表單數(shù)據(jù)驗(yàn)證
使用第三方包來(lái)數(shù)據(jù)驗(yàn)證;
1惠遏、安裝joi:為表單中攜帶的數(shù)據(jù)項(xiàng)砾跃,定義驗(yàn)證規(guī)則,根目錄下終端執(zhí)行命令:npm i joi节吮;
2抽高、安裝:@escook/express-joi中間件,來(lái)實(shí)現(xiàn)自動(dòng)對(duì)表單數(shù)據(jù)進(jìn)行驗(yàn)證透绩;
3翘骂、在scheme文件夾下新建user.js,用來(lái)存放一些用戶(hù)驗(yàn)證規(guī)則帚豪;
// 用戶(hù)信息驗(yàn)證規(guī)則模塊
// 導(dǎo)入joi第三方模塊
const joi = require('joi')
// 定義用戶(hù)名和密碼的驗(yàn)證規(guī)則
// string() 值必須是字符串
// alphanum() 值只能包含a-zA-Z的字符串
// min(1).max(10) 最大長(zhǎng)度碳竟, 最小長(zhǎng)度
// required() 值是必填項(xiàng)
// pattern() 值必須符合正則表達(dá)式
const username = joi.string().alphanum().min(1).max(10).required()
const password = joi.string().pattern(/^[\S]{6,12}$/).required()
// 定義驗(yàn)證注冊(cè)和登錄表單數(shù)據(jù)的規(guī)則對(duì)象 再對(duì)外共享
exports.reg_login_schema = {
body: {
username,
password
}
}
在router文件夾下的user.js中,導(dǎo)入@escook/express-joi中間件和需要驗(yàn)證規(guī)則的對(duì)象狸臣,在路由器中url后插入中間件莹桅;
// 導(dǎo)入驗(yàn)證表單數(shù)據(jù)的中間件
const expressJoi = require('@escook/express-joi')
// 導(dǎo)入需要驗(yàn)證規(guī)則的對(duì)象
const { reg_login_schema } = require('../schema/user')
// 創(chuàng)建路由對(duì)象
const userRouter = express.Router()
// 導(dǎo)入用戶(hù)路由處理函數(shù)模塊
const user_hander = require('../router_hander/user')
// 掛載路由 注冊(cè)新用戶(hù)
// 在路由中,聲明局部中間件,對(duì)當(dāng)前請(qǐng)求中攜帶的數(shù)據(jù)進(jìn)行驗(yàn)證
// 數(shù)據(jù)驗(yàn)證通過(guò)后,會(huì)把這次請(qǐng)求流轉(zhuǎn)給后面的路由處理函數(shù)
// 數(shù)據(jù)驗(yàn)證失敗后,終止后續(xù)代碼的執(zhí)行,并跑出一個(gè)全局Error錯(cuò)誤,進(jìn)入全局錯(cuò)誤級(jí)別中間件中進(jìn)行處理
userRouter.post('/reguser', expressJoi(reg_login_schema), user_hander.regUser)
如果驗(yàn)證失敗則調(diào)用錯(cuò)誤中間件烛亦,在app.js中導(dǎo)入joi模塊诈泼;
// 導(dǎo)入 joi 模塊
const joi = require('joi')
// 導(dǎo)入并注冊(cè)路由模塊
const userRouter = require('./router/user')
app.use('/api',userRouter)
//定義錯(cuò)誤級(jí)別的中間件
app.use((err, reg, res, next) => {
// 注意 此處一定要加return 終止 不然會(huì)連續(xù)調(diào)用兩次res.send()程序,會(huì)報(bào)錯(cuò)
if(err instanceof joi.ValidationError) return res.cc(err)
// 未知的錯(cuò)誤
res.cc(err)
})
router_hander文件夾下的user.js中煤禽,處理函數(shù)的路由代碼如下:
// 注冊(cè)新用戶(hù)的處理函數(shù)
exports.regUser = (req, res) => {
// 檢測(cè)用戶(hù)名是否合法
const userinfo = req.body
// 對(duì)表單中的數(shù)據(jù)進(jìn)行合法性的校驗(yàn)
// 當(dāng)userinfo.username 或者 userinfo.username = false
// 沒(méi)有對(duì)應(yīng)數(shù)據(jù)或者屬性時(shí)則顯示false
// if(!userinfo.username || !userinfo.username) {
// return res.send({
// status: 1,
// message: '用戶(hù)用戶(hù)名或密碼不合法!'
// })
// }
// 檢測(cè)用戶(hù)名是否被占用
// 1.定義SQL語(yǔ)句铐达,檢測(cè)用戶(hù)名是否被占用
const sqlStr = 'select * from my_dv_01.dv_users where username=?'
// 2.執(zhí)行SQL語(yǔ)句
db.query(sqlStr, userinfo.username, (err, results) => {
if(err) {
// return res.send({
// status: 1,
// message: err.message
// })
return res.cc(err)
}
// 當(dāng)userinfo.username的長(zhǎng)度大于0,說(shuō)明當(dāng)前用戶(hù)名已存在
if(results.length > 0) {
// return res.send({
// status: 1,
// message: '用戶(hù)名被占用檬果,請(qǐng)選擇其他用戶(hù)名娶桦!'
// })
return res.cc('用戶(hù)名被占用,請(qǐng)選擇其他用戶(hù)名!')
}
// TODO:使用bcryptjs對(duì)用戶(hù)密碼進(jìn)行加密處理
// 1.下載包 npm i bcryptjs@2.4.3
// 2.導(dǎo)入包
// 3.調(diào)用bcrypt.hashSync()的方法對(duì)密碼進(jìn)行加密,10能提高密碼安全 性衷畦,把加密后的結(jié)果再賦值給userinfo.password
console.log(userinfo);
// password: '000000'
userinfo.password = bcrypt.hashSync(userinfo.password, 10)
console.log(userinfo);
// password: '$2a$10$H75J0rWlVeiQh4yhQfsrWumWmcEEQgHZ9HvMMXqvL.n.ZpXP8Tj1y'
// 插入新用戶(hù)
// 1.定義SQL語(yǔ)句
const sql = 'insert into my_dv_01.dv_users set ?'
// 2.執(zhí)行SQL語(yǔ)句
db.query(sql,{username: userinfo.username, password: userinfo.password}, (err, results) => {
if(err)
// res.send({
// status: 1,
// message: err.message
// })
return res.cc(err)
if(results.affectedRows !== 1)
// res.send({
// status: 1,
// message: '插入新用戶(hù)失敗栗涂,請(qǐng)稍后再試!'
// })
return res.cc('插入新用戶(hù)失敗祈争,請(qǐng)稍后再試斤程!')
// 注冊(cè)用戶(hù)成功
// res.send({
// status: 0,
// message: '插入新用戶(hù)成功!'
// })
res.cc('插入新用戶(hù)成功菩混!',0)
})
})
}
用戶(hù)登錄的接口
1忿墅、檢測(cè)表單數(shù)據(jù)是否合法