阶段一
1 初始Node.js
javascript 运行环境
1.2 Node.js中的javacript 运行环境
1.3 Node.js环境安装
百度
1.4 node.js 执行javaScript 代码
2 fs文件系统模块
2.1 fs文件系统模块概念
导入文件系统模块:
const fs = require('fs')
-
fs.readFile()
// 1 导入fs文件系统模块 const fs = require('fs') // 2 调用 fs.readFile() 方法读取文件 fs.readFile('text.txt','utf8',function(err,res){ // 打印结果:1 读取成功 err值为 null // 2 读取失败 err值为错误对象 res值为undefined console.log(err) console.log('----------') console.log(res) })
效果:
判断文件读取成功还是失败(err.message)
const fs = require('fs') fs.readFile('text.txt','utf8',function(err,res){ if(err) { console.log("读取文件失败!"+err.message) }else { console.log("读取文件成功!"+res) } })
-
fs.writeFile()
const fs = require('fs') const str = '在长城 黄河' fs.writeFile('tex.txt',str,'utf8',function(err){ if(err) { console.log('写入失败!'+err.message) }else { console.log('写入成功!') } })
2.2 案例: 文件中成绩整理
score.txt 文件中:
小明=92 小兰=99 小绿=87 小马=77 小环=45
const fs = require('fs')
fs.readFile('score.txt','utf8',function(err,res) {
if(err) {
console.log('文件获取失败!',err.message)
}
console.log(res)
let oldScore = res.split(' ')
let newScore = []
oldScore.forEach(item => {
newScore.push(item.replace('=',':'))
})
newScore = newScore.join("/t/n")
console.log(newScore)
fs.writeFile('score.txt',newScore,function(err) {
if(err){
console.log('写入失败!'+err.message)
}
console.log('写入成功!')
})
})
效果:
2.3 路径拼接问题
注意:在js中,/ 是转义字符的意思
直接提供完整路径,缺点:移植性非常差,不利于维护
解决:__dirname (表示当前文件所处的目录)
示例:
const fs = require('fs')
console.log(__dirname)
fs.readFile(__dirname+'//text.txt','utf8',function(err,res){
if(err) {
console.log("读取文件失败!"+err.message)
}else {
console.log("读取文件成功!"+res)
}
})
3 path 路径模块
3.1 puth 路径模块概念
path.extname()方法,获取路径中的扩展名
示例 1- path.join():
const path = require('path')
// 将多个路径片段拼接在一起
const pathStr = path.join('/a','/b/c', '../','/d','e') // /a/b/d/e
console.log(pathStr)
const pathStr2 = path.join(__dirname, './files/1.txt')
示例2:path.basename()
const path = require('path')
const fpath ='/a/b/c/index.html'
var fullName = path.basename(fpath)
console.log(fullName) // 输出 index.html
var nametext = path.basename(fpath,'.html') // 输出 index
console.log(nametext)
示例3:path.extname - 获取路径中的扩展名
const path = require('path')
const fpath ='/a/b/c/index.html'
const fext = path.extname(fpath) // .html
console.log(fext)
3.2 综合案例 - 页面拆分
// 导入fs 模块
const fs = require('fs')
// 导入 path 模块
const path = require('path')
// 使用正则表达式 分别匹配 标签 /s - 表示空白字符 /S - 表示非空白字符
// * - 表示任意匹配
const regStyle = /<style>[/s/S]*<//style>/
const resScript = /<script>[/s/S]*<//script>/
// 导出 模块
module.exports.separate = function(filename) {
fs.readFile(path.join(__dirname,filename),'utf8',function(err,res) {
if(err) {
console.log('文件打开失败!',err.message)
}else {
// console.log('文件打开成功!')
resolveCss(res)
resolveJs(res)
resolveHtml(res)
}
})
}
function resolveCss(str) {
let regStr =regStyle.exec(str)
// console.log(regStr[0].replace('<style>','').replace('</style>',''))
let newRegStr = regStr[0].replace('<style>','').replace('</style>','')
fs.writeFile(path.join(__dirname,'/indexItem/indexCss.css'),newRegStr,'utf8',function(err){
if(err)
console.log('写入失败',err.message)
// else
// console.log('写入成功')
})
}
function resolveJs(str) {
let regStr = resScript.exec(str)
let newRegStr = regStr[0].replace('<script>','').replace('</script>','')
fs.writeFile(path.join(__dirname,'/indexItem/indexJs.js'),newRegStr,'utf8',function(err){
if(err)
console.log('写入失败',err.message)
// else
// console.log('写入成功')
})
}
function resolveHtml(str) {
let replaceStr = str.replace(regStyle,'<link rel="stylesheet" href="indexCss.css">').replace(resScript,'<script src="indexJs.js"></script>')
fs.writeFile(path.join(__dirname,'/indexItem/indexHtml.html'),replaceStr,'utf8',function(err){
if(err)
console.log('写入失败',err.message)
// else
// console.log('写入成功')
})
}
4 http 模块(一个web服务)
4.1 http的概念
const http = require('http')
http.createServer()
4.2 创建基本web服务器
// 1 导入 http 模块
const http = require('http')
// 2 创建 web 服务器实例
const server = http.createServer()
// 3 为服务器实例绑定request 事件 监听客户端的请求
server.on('request',function(req,res){
console.log('someone visit out web server')
})
// 4 启动服务器
server.listen(8080,function(){
console.log('server running at http://127.0.0.1:8080')
})
req 是请求的对象 包含与客户端相关的数据或属性
示例:
const http = require('http')
const server = http.createServer()
server.on('request',(req,res) => {
// req.url 是客户端请求的URL地址
// req.method 是客户端的method 请求类型
const str = `your url is ${req.url}, method is ${req.method}`
console.log( str)
})
server.listen(80,()=> {
console.log('server at http://127.0.0.1')
})
res 响应对象 res.end()
示例:
const http = require('http')
const server = http.createServer()
server.on('request',(req,res) => {
const str = `your url is ${req.url}, method is ${req.method}`
console.log( str)
// 调用 res.end 响应客户端并发送数据
// const data = {
// id: 11011,
// name: 'liming',
// age: 18,
// address: 'wenli'
// }
res.end('test api')
})
server.listen(80,()=> {
console.log('server at http://127.0.0.1')
})
4.3 解决res响应对象时,中文乱码
手动设置编码格式
示例:
const http = require('http')
const server = http.createServer()
server.on('request',(req,res) => {
const str = `url 是 ${req.url}, method 是 ${req.method}`
// 防止中文乱码 设置响应头 'Content-type','text/html; charset=utf-8'
res.setHeader('Content-type','text/html; charset=utf-8')
res.end(str)
})
server.listen(80,()=> {
console.log('at http://127.0.0.1')
})
4.4 根据不同的url响应不同的html内容
示例:
const http = require('http')
const server = http.createServer()
server.on('request',(req,res) => {
const url = req.url
console.log(url)
let content = '<h2>404 not found!</h2>'
if(url == '/' || url == '/index.html'){
content = '<h2>首页</h2>'
}else if(url == '/about.html') {
content = '<h2>关于</h2>'
}
res.end(content)
})
server.listen(80,()=> {
console.log('at http://127.0.0.1')
})
4.5 web服务器案例 - 优化资源请求
const http = require('http')
const fs = require('fs')
const path = require('path')
const server = http.createServer()
server.on('request',(req,res)=> {
const url = req.url
// /index.html /
// const fpath = path.join(__dirname,url)
let fpath = ''
if(url === '/'){
fpath = path.join(__dirname,'/indexItem/indexHtml.html')
} else {
// 重点 拼接成请求路径
fpath = path.join(__dirname,'/indexItem'+url)
}
// console.log(fpath)
fs.readFile(fpath,'utf8',(err,dataStr)=>{
if(err)
return res.end('404 not found !')
else
res.end(dataStr)
})
})
server.listen(80,()=> {
console.log('at http://127.0.0.1')
})
4.5 模块化 - common.js
4.5.1 模块化的定义
4.5.2 node.js 中的模块化
加载模块
模块作用域
模块作用域的好处
防止全局变量污染
每个模块都有一个 module 对象
笔记: 在外界使用require 导入一个自定义模块的时候,得到的成员,就是那个模块中,通过module.exports 指向的那个对象
4.5.3 在module.exports 对象上挂载属性和方法
写法1 (不建议)
const username = "lisi"
const age = 18
module.exports.sayme = function () {
console.log('my name is' + username)
}
module.exports.age = age
效果:
写法2 (建议)
module.exports = {
username : 'zhanghua',
sayme() {
console.log('my name is '+ this.username)
}
}
4.5.4 exports 与 module.exports指向的对象
// 不行
// exports = {
// username : 'zhanghua',
// sayme() {
// console.log('my name is '+ this.username)
// }
// }
// 可以
const username = 'wangliu'
exports.username = username
exports.sayme = function () {
console.log("my name is " + username)
}
注意:
exports 与 module.exports的使用误区?
误区1 :
exports.username = 'zs'
module.exports = {
gender: '男',
age:18
}
效果:
因为引用数据类型,地址指向问题
误区3
exports.username = 'ls'
exports.age= 19
效果:
原因:没有定义引用数据类型,不会改变地址
误区4
exports = {
username : 'zs',
gender: "女"
}
module.exports = exports
module.exports.age = 22
效果:
4.5.5 node.js 模块化规范
问题:为什么nodejs不支持import语法
nodejs不支持import语句,原因:nodejs采用的是CommonJS的模块化规范,使用require语句引入模块;而import是ES6的模块化规范关键字。
解决:babel的安装
阶段二
1 npm与包
概念:
介绍:
1.2 npm 导入moment包
-
npm install moment // 安装包
1.3 包的语义化管理规范
1.4 包的分类
npm intall 包名 -D // devDependencies
npm intall 包名 // dependencies
全局包
npm intall 包名 -g
npm unintall 包名 -g // 卸载包
1.5 推荐包(i5ting_toc) - xx.md文件转 xx.html 件
1.6 规范的包内部结构
1.7 开发自己的包
-
文件结构
-
文件中代码结
package.json
{ "name": "codexxx-tools", "version": "1.0.0", "main": "index.js", "description": "提供格式化时间, htmlEscape相关功能", "keywords": [ "codexxx", "dateFormat", "escape" ], "license": "ISC" }
index.js
// 格式化时间 function dateFormat(dataStr) { const dt = new Date(dataStr) const y = padZero(dt.getFullYear()) const m = padZero(dt.getMonth() + 1) const d = padZero(dt.getDate()) const hh = padZero(dt.getHours()) const mm = padZero(dt.getMinutes()) const ss = padZero(dt.getSeconds()) return `${y}-${m}-${d} ${hh}:${mm}:${ss}` } // 定义补零操作 function padZero(n) { return n > 9 ? n : '0'+n } // html 转义处理 function htmlEscape(str) { return str.replace(/<|>|"|&/g, (match)=> { switch(match) { case '<': return '<' case '>': return '>' case '"': return '"' case '&': return '&' } }) } function htmlUnEscape(str) { return str.replace(/<|>|"|&/g, (match)=> { switch(match) { case '<': return '<' case '>': return '>' case '"': return '"' case '&': return '&' } }) } // 导出 module.exports = { dateFormat, htmlEscape, htmlUnEscape }
-
分模块
使用:...
const date = require('./src/dateFormat.js') const escape = require('./src/htmlEscape.js') module.exports = { ...date, ...escape }
-
编写包的开源文档
README.md
## 安装 ``` npm install codexxx-tools ``` ## 导入 ```js const codexxx = require('codexxx-tools') ``` ## 格式化时间 ```js // 调用 dateFormat 格式化时间 const dt = codexx.dateFormat(new Date()) // 结果 2022-12-04 23:19:50 console.log(dt) ``` ## 转义 html 中的特殊字符 ```js // 待转义的字符 const str = '<h2>hello world !</h2>' // 调用 htmlEscape 转义字符 const newStr = codexx.htmlEscape(str) // 结果 <h2>hello world !</h2> console.log(newStr) ``` ## 还原 html 中的特殊字符 ```js // 待还原的字符 const newStr = codexx.htmlEscape(str) // 结果 <h2>hello world !</h2> console.log(codexx.htmlUnEscape(newStr)) ``` ## 开源协议 ISC
1.8 发布包
1.8.1 发布包 删除包
百度
1.9 模块的加载机制
1.9.1 优先从缓存中加载
1.9.2 内置模块的加载机制
1.9.3 自定义模块的加载机制
1.9.4 第三方模块的加载机制
1.9.5 把目录作为模块加载
阶段三:Express
1 express 的初步使用
安装
npm install express
1.2 express 的使用
1.2.1 创建 web 服务器
// 1 导入 express
const express = require('express')
// 2 创建 web 服务器
const app = express()
// 3 调用 app.listen(端口号 启动成功后返回回调函数)
app.listen(80,()=> {
console.log('express server runing at http://127.0.0.1')
})
1.2.2 发起get和post请求
// 1 导入 express
const express = require('express')
// 2 创建 web 服务器
const app = express()
// 4 监听客户端 get 和 post 请求, 并向客户端响应数据
app.get('/user',(req, res)=> {
// 调用 express 提供的res.send() 方法, 向客户端 响应一个json 对象 或 文本字符串
res.send({name: 'zs', age: 20,gender: '男'})
})
app.post('/user',(req, res) => {
res.send('请求成功')
})
// 3 调用 app.listen(端口号 启动成功后返回回调函数)
app.listen(80,()=> {
console.log('express server runing at http://127.0.0.1')
})
1.2.3 获取url中携带的查询参数 - req.query
// url 是 http://127.0.0.1/user?username=aaa&age=18
app.post('/user',(req, res) => {
console.log(req.query) // { username: 'aaa', age: '18' }
res.send('请求成功')
})
1.2.4 获取url中携带的动态参数 - req.params
// 可以有多个动态参数
app.get('/user/:uname/:id',(req, res)=> {
res.send(req.params)
})
1.3 托管静态资源 - express.static()
app.use(express.static('./indexItem'))
// express.static('路径') 方法中的路径不会出现在客户端的访问路径中
注意:自动托管文件夹,并在其目录下自动寻找index.html/htm 等文件
1.3.2托管多个静态资源目录
app.use(express.static('./indexItem'))
app.use(express.static('./images'))
// 直接重开一行 写就行
1.3.3 挂载路径前缀
app.use('/images',express.static('./images'))
1.4 nodemon 的使用
1.4 介绍
安装
npm install nodemon -g
使用
// 终端中
nodemon xx.js
2 express 路由
2.1 路由概念
// 示例
app.post('/user',(req, res) => {})
2.2 路由的使用
2.2.1 路由最简单的使用
// 挂载路由
app.post('/user',(req, res) => {})
2.2.2 重点 - 模块化路由
示例:
示例代码:
文件结构
// login.js
const express = require('express')
const router = express.Router()
router.get('/login', (req, res) => {
res.send('welcome use API !')
})
router.post('/login', (req, res) => {
res.send('login success !')
})
module.exports = router
// api.js
const express = require('express')
const app = express()
// 注册路由模块
const login = require('./login')
// 导入路由模块
app.use(login)
// app.use() 函数的作用 注册全局中间件
app.listen(80,()=> {
console.log('at 127.0.0.1')
})
注意:为模块统一添加前缀
// 注册路由模块
const login = require('./login')
// 导入路由模块
app.use('/api',login)
// app.use() 函数的作用 注册全局中间件
3 express 中间件
3.1 中间件的概念
3.1.2 express中间件的格式
app.get('/',(req, res, next)=>{
next()
})
3.1.3 中间件 - next 函数的作用
3.2 expres 中间件的使用
3.2.1 全局生效的中间件
附:定义注册中间件 简化写法
示例:
const express = require('express')
const app = express()
// 定义中间件
const mw = function(req,res,next) {
console.log('中间件')
next()
}
// 将 mw 注册为全局生效的中间件
app.use(mw)
// 注册中间件 简化写法
//app.use(function(req,res,next) {
// console.log('中间件')
// next()
//})
app.get('/',(req,res)=> {
console.log('/ 路由')
res.send('index page')
})
app.get('/login',(req,res)=> {
console.log('/login 路由')
res.send('login page')
})
app.listen(80,()=> {
console.log('at http://127.0.0.1')
})
3.2.2 中间件的作用
......
// 定义中间件
const mw = function(req,res,next) {
console.log('中间件')
const dt = new Date()
// req 上添加属性
req.newTime = dt
next()
}
// 将 mw 注册为全局生效的中间件
app.use(mw)
......
3.2.3 定义多个全局中间件
// 定义多个全局中间件
app.use((req,res,next)=> {
console.log('第一个中间件')
next()
})
app.use((req,res,next)=> {
console.log('第二个中间件')
next()
})
3.2.4 局部生效的中件件
// 局部中间件
const mw1 = (req, res, next) => {
console.log('中间件')
next()
}
// 使用局部中间件
app.get('/',mw1,(req, res,next)=> {
res.send('test file')
})
3.2.5 定义多个局部中间件
注册中间件的等价写法
// 局部中间件
const mw1 = (req, res, next) => {
console.log('中间件')
// 一定要调用 next() 执行下一个中间件
next()
}
// 多个局部中间件
const mw2 = (req,res,next) => {
console.log('中间件2')
next()
}
// 使用局部中间件
// 等价写法
// app.get('/',[mw1,mw2],(req, res,next)=> {
// res.send('test file')
//})
app.get('/',mw1,mw2,(req, res,next)=> {
res.send('test file')
})
3.2.6 中间件的注意事项
3.3 中间件的分类
express 官方把常见的中间件分为五大类:
3.3.1 应用级别中间件:
3.3.2 路由级别中间件:
var app = express()
var router = experss.Router()
// 路由级别的中间件
router.use((req,res,next)=> {
console.log('Time',Date.now())
next()
})
app.use('/',router)
3.3.3 错误级别的中间件
app.get('/',function(req,res){
// 人为制造错误
throw new Error('人为服务器错误')
res.send('home page')
})
app.use((err,req,res,next)=>{
console.log('发生错误:' + err.message)
res.send('Eorror' + err.message)
})
注意:错误级别的中间件,必须注册在所有路由之后
3.3.4 express 内置的中间件
// 配置 application/json 格式数据的内置中间件
app.use(express.json())
// 配置解析 application/x-www-form-urlencoded 格式数据的内置中间件
app.use(express.urlencoded({extended: false}))
express.json 的使用
在软件,模拟发起post请求:
注意:默认情况下 如果不解析 表单数据的中间件 则 res.body 等于 undefined
// 通过 express.json 中间件, 解析 json 格式表单数据
app.use(express.json())
app.post('/',(req,res,next)=> {
// 默认情况下 如果不解析 表单数据的中间件 则 res.body 等于 undefined
console.log(req.body)
res.send('ok')
})
express.urlencoded({extended: false}) 的使用
app.use(express.urlencoded({extended: false}))
app.post('/',(req,res,next)=> {
// 默认情况下 如果不解析 表单数据的中间件 则 res.body 等于 undefined
console.log(req.body)
res.send('ok')
})
3.3.5 第三方中间件
3.4 自定义中间件
3.4.1 需求与步骤
3.4.2 自定义中间件
// 解析表单数据的中间件
app.use((req,res,next)=> {
// 具体
})
3.4.3 监听req的data事件
// 定义变量 用来存客户端发送过来的请求数据
let str = ''
// 监听 req 对象的 data 事件(客户端发送的新的请求数据)
req.on('data', (chunk) => {
// 拼接请求体数据 隐式转换为字符串
str += chunk
})
3.4.4 监听req的end事件
// 监听 req 对象的 end 事件 (请求体发送数据完成后自动触发)
req.on('end',()=>{
// 打印完整的请求数据
console.log(str) // 结果: bookname=%E7%9C&author=%E6%
})
3.4.5 querystrign 解析请求体数据
问题:“querystring”已弃用
解决: Nodejs提取网址参数,解决“querystring”已弃用
// 导入处理 querystring
const qs = require('querystring');
......
// 调用 qs.parse() 方法 把查询字符串解析为对象
const body = qs.parse(str)
console.log(body)
3.4.6 将解析出来的数据挂载在 req.body
// 调用 qs.parse() 方法 把查询字符串解析为对象
const body = qs.parse(str)
// console.log(body)
// 将数据挂载在req.body
req.body = body
.....
app.post('/user',(req,res,next)=> {
// req 对象的数据
// console.log(req.body)
res.send(req.body)
})
3.4.7 自定义中间件封装为独立模块
补充(未分模块的代码):
const express = require('express')
// 导入处理 querystring
const qs = require('querystring');
const app = express()
// 解析表单数据的中间件
app.use((req, res, next) => {
// 具体
// 定义变量 用来存客户端发送过来的请求数据
let str = ''
// 监听 req 对象的 data 事件(客户端发送的新的请求数据)
req.on('data', (chunk) => {
// 拼接请求体数据 隐式转换为字符串
str += chunk
})
// 监听 req 对象的 end 事件 (请求体发送数据完成后自动触发)
req.on('end', () => {
// 打印完整的请求数据
// console.log(str) // 结果: bookname=%E7%9C&author=%E6%
// ps :
// 调用 qs.parse() 方法 把查询字符串解析为对象
const body = qs.parse(str)
// console.log(body)
// 将数据挂载在req.body
req.body = body
next()
})
})
app.post('/user',(req,res,next)=> {
// req 对象的数据
// console.log(req.body)
res.send(req.body)
})
app.listen(80, () => {
console.log('at http://127.0.0.1')
})
4 使用 express 写接口
4.1/2/3/4 express基本创建
-
创建基本服务器
// api.js 文件 const express = require('express') const app = express() app.use(express.urlencoded({extended: false})) // 导入路由模块 const login = require('./login') // 注册路由模块 app.use('/api',login) app.listen(80,()=>{ console.log('server at http://127.0.0.1') })
-
路由模块
// login.js 文件 const express = require('express') const apiRouter = express.Router() // 挂载对应的路由 // get 请求 apiRouter.get('/login',(req,res,next)=> { const query = req.query res.send({ status: 200, msg: 'get 请求成功!', data: query }) }) apiRouter.post('/login',(req,res,next)=> { const body = req.body res.send({ status: 200, msg: 'post 请求成功!', data: body }) }) module.exports = apiRouter
4.5 CORS 跨域资源共享
解决跨域问题:
4.5.2 使用
4.5.3 cors 介绍
4.5.4 cors 注意事项
4.5.5 cors 响应头部 Access-Control-Allow- Origin
4.5.6 cors 响应头部 Access-Control-Allow- Headers
4.5.7 cors 响应头部 Access-Control-Allow- Methods
4.5.8 cors 请求的分类
简单请求:
预检请求:
简单请求与预简请求的区别:
示例:
// login.html
...
// delete 请求
$('.deleteBtn').on('click',function(){
$.ajax({
type: 'delete',
url: 'http://127.0.0.1/api/login',
// data: {data:'zs',age:18},
success: function(res){
console.log(res)
}
})
})
...
// login.js
...
apiRouter.delete('/login',(req,res,next)=> {
res.send({
status: 200,
msg: 'delete 请求成功!'
})
})
...
效果:
4.6 JSONP的概念与特点及使用
4.6.2 创建JSONP接口的注意事项
4.6.3 实现JSONP接口的具体代码
4.6.4 在jquery 中 发起jsonp请求
阶段四
4 在项目中操作mysql
4.1/2 安装与配置mysql 模块
-
安装
npm install mysql
-
配置
// 1 导入 mysql 模块 const mysql = require('mysql') // 2 建立与 mysql 之间的关系 const db = mysql.createPool({ host: '127.0.0.1', // 数据库的ip user: 'root', password: '123', database: 'my_db' })
-
测试mysql 模块是否工作正常
db.query('select 1',(err,res)=> { // 如果模块工作期间报错 if(err) return console.log(err.message) // 成功 console.log(res) // [ { '1': 1 } ] })
注意:node.js 连接 mysql 8 失败问题
(2)、在node项目中更换mysql连接器
npm un mysql && npm i mysql2 // 导入myslq模块 const mysql = require('mysql2')
4.3 使用MySQL操作数据库
4.3.1 查询数据
const sqlStr = 'select * from users'
db.query(sqlStr,(err,res)=> {
if(err) return console.log(err.message)
console.log(res)
})
4.3.2 插入数据
方式一
// 1 要插入到user 表中的数据对象
const user = {username: 'xiaoming', password: '123123'}
// 2 待执行 sql 语句 , 其中英文 ? 表示占位符
const sqlStr = 'insert into users (username, password) values (?,?)'
// 3 使用数组形式 , 依次为 ? 指定具体的值
db.query(sqlStr,[user.username,user.password],(err,res)=> {
if(err) return console.log(err.message)
// affectedRows 表示执行这条 sql 语句,影响的行数
if(res.affectedRows === 1) {
console.log('插入数据成功')
}
})
方式二
// 插入数据的便捷方式
const user = {username: 'gangzi',password: 'pc4123'}
// 编辑写法 set ?
const sqlStr = 'insert into users set ?'
// 互相对应
db.query(sqlStr,user,(err,res)=> {
if(err) return console.log(err.message)
if(res.affectedRows === 1) {
console.log('插入数据成功')
}
})
4.3.3 更新数据
写法一
更新数据
const user = {username: 'lilisi',password:'aa113',id: 6}
const sqlStr = 'update users set username = ? , password = ? where id = ?'
db.query(sqlStr,[user.username,user.password,user.id],(err,res)=> {
if(err) return console.log(err.message)
if(res.affectedRows === 1)
console.log('数据更新成功')
})
写法二(便捷)
// 更新数据 - 便捷写法
const user = {username: 'lihua',password:'lh122',id: 6}
const sqlStr = 'update users set ? where id = ?'
// 注意 写法
db.query(sqlStr,[user,user.id],(err,res)=> {
if(err) return console.log(err.message)
if(res.affectedRows === 1)
console.log('数据更新成功')
})
4.3.4 删除数据
// 删除数据
const sqlStr = 'delete from users where id = ?'
db.query(sqlStr,6,(err,res)=> {
if(err) return console.log(err.message)
if(res.affectedRows === 1)
console.log('数据删除成功')
})
4.3.5 标记删除 - 用户体验思维
// 标记删除
const sqlStr = 'update users set status = ? where id = ?'
db.query(sqlStr,[1,20],(err,res)=> {
if(err) return console.log(err.message)
if(res.affectedRows === 1)
console.log('数据更新成功')
})
5 前后端的身份认证
5.1 前后端的概念
5.1.2 服务端的优缺点
5.1.3 前后端分离的优缺点
5.1.4 选择web开发的模式
5.2 身份认证
5.2.3 不同的开发模式下 选择不同
5.2.4 Session 认证机制
5.2.5 cookie 在身份认证中的作用
5.3.5 cookie 不具有安全性
提高身份认证的安全性
在客户端出示cookie后,还需要在服务端进行cookie的认证
5.4 在express中使用Session认证
5.4.1 安装express-session中间件
npm install express-session
5.4.2 配置express-session中间件
通过app.use()注册中间件
5.4.3 向session中存数据
5.4.4 从session中取数据-验证是否已经登录
5.4.5 清空session的数据-退出登录
5.5 JWT认证机制
5.5.1 jwt 使用时机
5.5.4 jwt 的组成
5.5.7 jwt的使用方式
5.6 在express 中使用jwt - (令牌)
5.6.1 安装相关的包
npm install jsonwebtoken express-jwt
5.6.2 导入包
const jwt = require('jsonwebtoken')
const expressJWT = require('express-jwt')
5.6.3 定义secret密钥
// secret 的本质是 一个字符串 越复杂越安全
// 建议命名 secretKey
const secretKey = 'lilisi ok'
5.6.4 在登录成功后生成JWT字符串
5.6.5 将jwt字符串还原成json对象
注意:更新后语法问题 - 解决Jwt遇到algorithms should be set报错的解决方法
5.6.6 用req.user 获取express-jwt解析的用户信息
5.6.7 捕获解析jwt失败后产生的错误
5.6.8 实机 - 测试 - 令牌验证代码
key:
Authorization
value:
Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNjcwNTExOTE5LCJleHAiOjE2NzA1MTE5Nzl9.tUg_VuYrusCyhFb3QLil-8aD17zsQKMbDFh0ZZTAsFo
代码:
// login.js
const express = require('express')
const app = express()
// jwt 认证
const jwt = require('jsonwebtoken')
const expressJWT = require('express-jwt')
// 定义密钥 secretKey
const secretKey = 'lilisi ok'
// 跨域
const cors = require('cors')
app.use(cors())
// 解析 urlcoded
app.use(express.urlencoded({
extended: false
}))
app.use(express.json())
// 注册中间件 将jwt字符串解析还原成json对象的中间件 unless({path:[...]}) 规定不需要 token就可以请求
// 注册 expressJWT 错误原因,版本一样,语法有更新 express-jwt@6.1.1 - 加 algorithms:['HS256']
// 把解析出来的用户信息 挂载在req.user 上
app.use(expressJWT({
secret: secretKey,
algorithms: ['HS256']
}).unless({
path: [/^//api///]
}))
// 登录接口
app.post('/api/login', (req, res) => {
const userinfo = req.body
// 登录失败
if (userinfo.username !== 'admin' || userinfo.password !== '000') {
return res.send({
status: 400,
msg: '登录失败'
})
}
// 登录成功
// 使用 jwt.sign 进行配置
// jwt.sign 里面的参数 不能对密码进行加密
const tokenStr = jwt.sign({
username: userinfo.username
}, secretKey, {
expiresIn: '60s'
})
res.send({
status: 200,
token: tokenStr,
msg: '登录成功'
})
})
// 一个有权限的 api
app.get('/admin/getinfo', (req, res) => {
// expressJWT 解析出来的用户信息 挂载在req.userreq.user
console.log(req.user)
res.send({
status: 200,
msg: '获取信息成功',
data: req.user
})
})
// 全局错误捕获中间件
app.use((err, req, res, next) => {
if (err.name === 'UnauthorizedError') {
return res.send({
status: 401,
msg: '无效的token'
})
}
// 其他原因的错误
res.send({
status: 500,
message: '未知错误'
})
})
app.listen(80, function () {
console.log('at http://127.0.0.1')
})
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 本地部署DeepSeek后,没有好看的交互界面怎么行!
· DeepSeek 解答了困扰我五年的技术问题。时代确实变了!
· 趁着过年的时候手搓了一个低代码框架
· 推荐一个DeepSeek 大模型的免费 API 项目!兼容OpenAI接口!