js 为什么在浏览器中可以执行
待执行的 js 代码 通过 JavaScript 解析引擎 执行
不同的浏览器使用不同的 JavaScript 解析引擎:
Chrome 浏览器 => V8
Firefox 浏览器 => OdinMonkey(奥丁猴)
Safri 浏览器 => JSCore
IE 浏览器 => Chakra(查克拉)
etc…
其中,Chrome 浏览器的 V8 解析引擎性能最好!
为什么 JavaScript 可以操作 DOM 和 BOM
每个浏览器都内置了 DOM、BOM 这样的 API 函数,因此,浏览器中的 JavaScript 才可以调用它们
运行环境是指代码正常运行所需的必要环境
V8 引擎负责解析和执行 JavaScript 代码。
内置 API 是由运行环境提供的特殊接口,只能在所属的运行环境中被调用。
node.js是一个基于chrome v8引擎的javascript运行环境
注:
Node.js 作为一个 JavaScript 的运行环境,仅仅提供了基础的功能和 API。然而,基于 Node.js 提供的这些基础能,很多强大的工具和框架如雨后春笋,层出不穷,所以学会了 Node.js ,可以让前端程序员胜任更多的工作和岗位:
基于 Express 框架(http://www.expressjs.com.cn/),可以快速构建 Web 应用
基于 Electron 框架(https://electronjs.org/),可以构建跨平台的桌面应用
基于 restify 框架(http://restify.com/),可以快速构建 API 接口项目
读写和操作数据库、创建实用的命令行工具辅助前端开发、etc…
总之:Node.js 是大前端时代的“大宝剑”,有了 Node.js 这个超级 buff 的加持,前端程序员的行业竞争力会越来越强!
LTS : 长期稳定版
Current : 新特性测试版
查看安装版本
node -v
console.log("Hello nodejs");
node 1.js
// Hello nodejs
fs 模块
用来 操作文件
的模块
js 中 导入
const fs = require('fs');
读写
const fs = require('fs');
// Read file
fs.readFile('../flies/1.md', 'utf8', (err, data) => {
if (err) {
console.log(err);
}
console.log(data);
});
// Write file
fs.writeFile('../flies/1.md', 'Hello Node.js', (err) => {
if (err) {
console.log(err);
}
console.log('File written successfully');
});
__dirname
: 当前文件目录
注:
fs.writeFlie() 只能创建文件 不能创建目录
fs.writeFlie() 重复执行新的内容会覆盖旧内容
path 模块
用来 处理路径
的模块
路径片段拼接
成一个完整的路径字文件名
解析出来导入
const path = require('path');
练习 path.join()
const fs = require('fs');
const path = require('path');
console.log(__dirname);
// Write file
fs.writeFile(path.join(__dirname, '../flies/1.md'), 'Hello World', (err) => {
if (err) throw err;
console.log('File created');
});
// Read file
fs.readFile(path.join(__dirname, '../flies/1.md'), 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
读取文件不在使用 + 号拼接 使用 path.join()
path.basename()
path.extname()
const fpath = "./flies/1.md";
console.log(path.basename(fpath)); // 1.md
// 移除扩展名
console.log(path.basename(fpath,'.md')); // 1
// 获取文件后缀名
console.log(path.extname(fpath)); // .md
console.log(path.basename(fpath, path.extname(fpath))); // 1
练习
将 ./flies/index.html 拆分成 ./shi.css ./shi.js ./shi.html
// 将 ./flies/index.html 拆分成 ./shi.css ./shi.js ./shi.html
const path = require('path');
const fs = require('fs');
// 定义正则表达式匹配 标签
const reg = / 标签
let cssStr = reg.exec(htmlStr);
// 如果匹配到了 标签
if (cssStr) {
// 将匹配到的 标签替换成空字符串
cssStr = cssStr[0].replace('','');
}
// 将 cssStr 写入到 ./css/shi.css 文件中
fs.writeFile(path.join(__dirname, '../css/shi.css'), cssStr, (err) => {
if (err) {
console.log("写入文件失败:" + err);
}
console.log("写入文件成功");
});
}
// 处理 js 文件
function resolveJs(htmlStr) {
// 使用正则表达式匹配 标签
let jsStr = reg2.exec(htmlStr);
// 如果匹配到了 标签
if (jsStr) {
// 将匹配到的 标签替换成空字符串
jsStr = jsStr[0].replace('','');
}
// 将 jsStr 写入到 ./js/shi.js 文件中
fs.writeFile(path.join(__dirname, '../js/shi.js'), jsStr, (err) => {
if (err) {
console.log("写入文件失败:" + err);
}
console.log("写入文件成功");
});
}
// 处理 html 文件
function resolveHtml(htmlStr) {
// 将 标签替换成
htmlStr = htmlStr.replace(reg, '');
// 将 标签替换成
htmlStr = htmlStr.replace(reg2, '');
// 将 替换后的文件 写入到 ./shi.html 文件中
fs.writeFile(path.join(__dirname, '../shi.html'), htmlStr, (err) => {
if (err) {
console.log("写入文件失败:" + err);
}
console.log("写入文件成功");
});
}
什么是 客户端 什么是 服务器?
在网络节点中 负责消费资源的电脑,叫做客户端
负责对外提供网络资源的电脑,叫服务器
http 模块 用来创建web服务器
的模块
http.createServer() 把一台普通电脑 变成 Web 服务器
导入
const http = require('http');
在 node.js 中 不需要 IIS,Apache 等 第三方服务器软件
通过几行简单的代码,就能轻松手写一个服务器软件
const http = require('http');
// 创建 web 服务器 为服务器添加监听事件
http.createServer().on('request', (req, res) => {
// 设置响应头
res.writeHead(200, {
'Content-Type': 'text/html;charset=utf-8'
});
// 设置响应体
const url = req.url;
// 判断不同的请求路径,返回不同的响应体
if (url === '/') {
res.end('Hello World
');
} else if (url === '/index.html') {
res.end('Hello World index
');
} else {
res.end('404 Not found!
');
}
// 打印客户端请求的 url 和 method
console.log(req.url);
console.log(req.method);
// 启动服务器
}).listen(8080, () => {
console.log('Server is running at http://localhost:8080');
}).on('error', (err) => {
console.log(err);
// 关闭服务器
}).on('close', () => {
console.log('Server is closed');
});
只要服务器接收到了客户端的请求,就会调用通过 server.on()
为服务器绑定的 request 事件处理函数
req
请求
req.url
是客户端请求的 URL 地址
req.method()
是客户端 请求的 method 请求类型
res
响应
res.end()
向客户端响应数据
模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程
。对于整个系统来说,模块是可组合、分解和更换的单元
把一个 大文件 拆分成 独立并且互相依赖的多个模块
内置模块
由 nodejs 官方提供 如 fs, path, http 等自定义模块
创建的每个 js 文件 都是自定义模块第三方模块
由第三方开发出来的模块 使用前需要下载加载自定义模块 可以省略 .js 后缀
// 加载自定义的模块
const m1 = require('./2.js');
在自定义模块中定义的变量,方法 只能在当前模块内被访问
防止全局作用域污染问题
模块作用域.js
const username = '张三';
function sayHello() {
console.log('Hello ' + username);
}
test.js
const custom = require('./模块作用域');
console.log(custom);
只能在当前模块访问
PS E:\project\front\node\nodeStudy\js> node .\test.js
{}
model.exports()
在 模块作用域.js 添加
module.exports = {username, sayHello};
PS E:\project\front\node\nodeStudy\js> node .\test.js
{ username: '张三', sayHello: [Function: sayHello] }
exports()
model.exports() 和 exports() 指向同一个对象
exports.username = username;
exports.sayHello = sayHello;
PS E:\project\front\node\nodeStudy\js> node .\test.js
{ username: '张三', sayHello: [Function: sayHello] }
最终都是以 model.exports() 指定的对象为准
nodejs 中的 第三方模块
就是 包
包是基于内置模块封装出来的
提供了更加高级,更加方便的 API ,极大的提高了开发效率
下载包
下载地址
可以通过 npm
直接下载
语法
npm install 包名
npm i 包名 # 简写
npm i 包名 -g # 全局安装
npm i [email protected] # 安装指定版本的包
卸载包
npm uninstall 包名
通过 淘宝npm镜像 提高 npm 下载速度
# 查看当前的下包镜像源
npm config get registry
# 将镜像源切换为淘宝镜像源
npm config get registry=https://registry.npm.taobao.org/
nrm
更方便切换下包镜像源
# 通过 npm 包管理器 将 nrm 安装为全局可用的工具
npm i nrm -g
# 查看所有可用的镜像源
nrm ls
# 切换淘宝镜像
nrm use taobao
i5ting_toc
一个可以将 md 文档转为 html 页面的小工具
npm i -g i5ting_toc
# md 转 html
i5ting_toc -f 1.md -o
结果如下
格式化时间
const moment = require('moment');
let dt = moment().format('YYYY-MM-DD HH:mm:ss');
console.log(dt);
PS E:\project\front\node\nodeStudy\js> node .\time.js
2022-06-08 15:45:22
npm 执行后项目会多一个 node_modules
和 package-lock.json
node_modules
: 存放所有已经安装到项目的包
package-lock.json
: 记录 node_modules 目录下的每一个包的下载信息
package.json
中记录了项目中安装了那些包 共享时只要把 package.json 共享即可
"dependencies": {
"jquery": "^3.6.0",
"moment": "^2.29.3"
}
在项目开发中 应该把 node_modules
文件夹 添加到 .gitignore
忽略文件中
接收到别人共享文件后
执行 npm i
就可以一次性安装所有的依赖性
npm i
会读取 package.json
中的所有依赖包 一次性下载
devDependencies
包只在项目开发阶段使用,在上线后不使用
dependencies
包在项目开发阶段和上线后都要使用
npm i 包名 -D # 记录到 devDependencies 节点中
npm i 包名 --save-dev # 完整写法
{
"dependencies": {
"jquery": "^3.6.0",
"moment": "^2.29.3"
},
"devDependencies": {
"webpack": "^5.73.0"
}
}
{
"name" : "xiaotao-tools",
"version" : "0.0.1",
"description" : "提供了格式化时间的工具",
"author" : "xiaotao",
"license" : "ISC",
"main" : "index.js",
"keywords" : ["time", "format" ,"xiaotao"],
"scripts" : {
"test" : "echo \"Error: no test specified\" && exit 1"
}
}
// 包的入口文件
// 定义格式化时间的函数
function formatDate(date, fmt) {
const dt = new Date(date);
const y = dt.getFullYear();
const m = padZero(dt.getMonth() + 1);
const d = padZero(dt.getDate());
const h = padZero(dt.getHours());
const i = padZero(dt.getMinutes());
const s = padZero(dt.getSeconds());
const ms = padZero(dt.getMilliseconds());
const week = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
const weekDay = week[dt.getDay()];
const time = `${h}:${i}:${s}`;
const dateTime = `${y}-${m}-${d} ${time}`;
const dateTimeWithWeek = `${y}-${m}-${d} ${time} ${weekDay}`;
const dateTimeWithWeekAndMs = `${y}-${m}-${d} ${time} ${weekDay} ${ms}`;
return `${y}-${m}-${d} ${h}:${i}:${s} ${weekDay}`;
}
// 定义一个补零的函数
function padZero(num) {
return num < 10 ? `0${num}` : num;
}
// 向外暴露一个格式化时间的函数
module.exports = {
formatDate
}
// 定义转义html字符的函数
function escapeHtml(html) {
return html.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '$quot;');
}
// 定义还原html字符的函数
function unescapeHtml(html) {
return html.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
}
dataFormat.js
htmlEscape.js
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dtZxesws-1689212097441)(C:\Users\xiaotao\AppData\Roaming\Typora\typora-user-images\image-20220608173607152.png)]
dateFormat.js
// 定义格式化时间的函数
function formatDate(date, fmt) {
const dt = new Date(date);
const y = dt.getFullYear();
const m = padZero(dt.getMonth() + 1);
const d = padZero(dt.getDate());
const h = padZero(dt.getHours());
const i = padZero(dt.getMinutes());
const s = padZero(dt.getSeconds());
const ms = padZero(dt.getMilliseconds());
const week = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
const weekDay = week[dt.getDay()];
const time = `${h}:${i}:${s}`;
const dateTime = `${y}-${m}-${d} ${time}`;
const dateTimeWithWeek = `${y}-${m}-${d} ${time} ${weekDay}`;
const dateTimeWithWeekAndMs = `${y}-${m}-${d} ${time} ${weekDay} ${ms}`;
return `${y}-${m}-${d} ${h}:${i}:${s} ${weekDay}`;
}
// 定义一个补零的函数
function padZero(num) {
return num < 10 ? `0${num}` : num;
}
module.exports = {
formatDate
}
escapeHtml.js
// 定义转义html字符的函数
function escapeHtml(html) {
return html.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '$quot;');
}
// 定义还原html字符的函数
function unescapeHtml(html) {
return html.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
}
module.exports = {
escapeHtml, unescapeHtml
}
index.js
// 包的入口文件
const formatDate = require('./src/dateFormat');
const escapeHtml = require('./src/escapeHtml');
// 向外暴露
module.exports = {
...formatDate, // ... 将里面的属性展开
...escapeHtml
}
README.md
npm install xiaotao-tools
const xiaotao = require('./xiaotao-tools');
let dt = xiaotao.formatDate(new Date());
console.log(dt);
// 结果 2022-06-08 17:35:39 星期三
let html = xiaotao.escapeHtml('你好
');
console.log(html);
// 结果 <h1>你好</h1>
console.log(xiaotao.unescapeHtml(html));
// 结果 你好
https://www.npmjs.com/ 注册一个账号
npm login
依次输入 用户名 密码 邮箱
登录之前必须切换为 官方镜像
发布 切换到包的根目录xiaotao-tools
npm publish
查看官网
npm unpublish 包名 --force
模块在第一次加载后会被缓存
多长调用 require() 不会重复执行
三种模块 都会 优先从缓存中加载 提高模块的加载效率
内置模块的优先级最高
Express 是基于 Nodejs 平台,快速 开放 极简 的 Web 开发框架
Express 的作用和nodejs 内置的 http 模块类型
本质: 就是一个 npm 第三方包 用于 快速创建 web 服务器
内置http 模块用起来复杂,开发效率低 Express 是基于 http 模块进一步封装出来的,能够极大提高开发效率
npm i express
const express = require('express');
// 创建 web 服务器 为服务器添加监听事件
const app = express();
// // 监听 get post 请求
app.get('/', (req, res) => {
res.send('Hello World');
}).get('/index.html', (req, res) => {
res.send('Hello World index');
}).get('/404', (req, res) => {
res.send('404 Not found!');
});
app.post('/', (req, res) => {
res.send('Hello World');
}).post('/index.html', (req, res) => {
res.send('Hello World index');
}).post('/404', (req, res) => {
res.send('404 Not found!');
});
// 设置响应头
app.listen(80, () => {
console.log('Server is running at http://localhost');
}).on('error', (err) => {
console.log(err);
}).on('close', () => {
console.log('Server is closed');
});
获取客户端发送过来的查询参数 默认是 一个 空对象
app.get('/', (req, res) => {
console.log(req.query);
res.send(req.query);
})
获取 url 中的 动态参数
app.post('/:id', (req, res) => {
res.send(req.params);
})
可以创建一个 静态资源服务器
// 将 public 下的 css js img 对外开放访问
app.use(express.static('public'))
const express = require('express');
const app = express();
// 将 public 下的 文件 对外开放访问
app.use(express.static('./public'))
app.listen(80, () => {
console.log('Server is running at http://localhost');
});
app.use(express.static('./public'))
app.use(express.static('./files'))
app.use('/static', express.static('../files'))
热部署工具
npm i -g nodemon
使用
node app.js
# 将上面的 node 替换为 nodemon
nodemon app.js
是 客户端的请求
与 服务器处理函数
之间的映射关系
组成
app.METHOD(PATH, HANDER)
// 请求类型 url 函数
app.get('/index.html', (req, res) => {
res.send('Hello World index');
})
为了方便对路由管理 express 不建议直接挂载到 app 上 而是推荐将路由抽离为单独的模块
步骤:
express.Router()
函数创建路由对象module.exports
向外共享路由对象app.use()
函数注册路由模块app.js
const express = require('express');
const app = express();
// 导入路由模块
const router = require('./router');
// 将路由模块挂载到 app 中
app.use(router);
app.listen(80, () => {
console.log('Server is running at http://localhost');
});
router.js
const express = require('express');
// 创建路由模块
const router = express.Router();
// 挂载具体路由
router.get('/user/list', (req, res) => {
res.send('get user list');
});
router.post('/user/add', (req, res) => {
res.send('add user');
});
// 向外导出路由模块
module.exports = router;
// 添加统一访问前缀
app.use('/api', router);
app.use('router')
就是一个中间件
作用: 对请求进行 预处理
中间件函数的形参列表中, 必须包含 next 参数
路由处理函数中只包含 req 和 res
多个中间件连续调用
的关键 把流转关系交给下一个 中间件 或 路由
const express = require('express');
const app = express();
// 定义 中间件 函数
const logger = (req, res, next) => {
console.log('logger');
// 调用 next 函数,放行下一个中间件
next();
}
app.listen(80, () => {
console.log('Server is running at http://localhost');
});
客户端发起的请求,到达服务器之后,都会执行的中间件
通过调用 app.use(中间件函数)
即可定义一个 全局中间件函数
// 全局中间件
app.use(logger);
可以做一些 类似于 日志的 处理
多个中间件之间 共享 同一份 req 和 res
我们可以在 上游
的中间件中,统一 为 req res 添加自定义的 属性 和 方法 ,供 下游
使用
const logger = (req, res, next) => {
console.log('logger');
req.a = 10;
// 调用 next 函数,放行下一个中间件
next();
}
app.use('logger')
app.get('/', (req, res) => {
console.log(req.a);
res.send('Hello World' + req.a);
});
// 定义 中间件 函数
const logger = (req, res, next) => {
console.log('logger');
req.a = 10;
// 调用 next 函数,放行下一个中间件
next();
}
// 多个全局中间件
app.use(logger).use((req, res, next) => {
console.log('use');
next();
});
app.get('/', (req, res) => {
console.log(req.a);
res.send('Hello World' + req.a);
});
不使用 app.use()
定义的中间件
// 定义局部中间件
const mw = (req, res, next) => {
console.log("这是局部中间件");
next();
}
// 该中间件只有在调用过的路由生效
// 可以同时调用多个中间件
app.get("/user", mw, mw2, (req, res) => {
res.send("调用了局部中间件:" + mw);
})
路由之前
注册必须写 next()
共享
同一个 req 和 res五大类
通过 app.use()
app.get()
app.post()
绑定到 app 实例上的中间件
// 全局中间件
app.use((req, res, next) => {
next();
});
// 局部中间件
app.get("/user", mw, (req, res) => {
res.send("user" );
})
绑定到 router
实例上的中间件
router.use(function (req, res, next) {
console.log("user");
next();
})
专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题
格式:
function(err, req, res, next)
必须有四个形参
app.get('/user/list', (req, res) => {
// 自定义一个错误
throw new Error("服务器发生错误");
// 导致后面代码不能正常执行
res.send('get user list');
});
// 定义一个错误级中间件
app.use((err, req, res, next) => {
if (err.status === 500) {
console.log('发生了错误' + err.message);
res.send('Error:' + err.message);
} else {
next();
}
});
快速托管静态资源
解析 json 格式的请求数据 (仅在 4.16.0+ 版本有用)
app.use(express.json())
解析 URL-encoded 格式的请求数据 (仅在 4.16.0+ 版本有用)
app.use(express.urlencoded({ extended: false }))
req.body
接收客户端发送过来的请求数据
处理 客户端表单数据
diy.js
const qs = require('querystring');
// 解析表单数据中间件
const bodyParser = (req, res, next) => {
// 定义一个 str 字符串 储存客户端发送过来的请求体数据
let str = '';
// 监听 req 的 data 事件
req.on('data', (chunk) => {
// 每次接收到客户端发送过来的数据,都会触发 data 事件
// chunk 是一个二进制数据流,需要转换成字符串
str += chunk;
});
// 监听 req 的 end 事件
req.on('end', () => {
// 当客户端发送完请求体数据后,会触发 end 事件
// 将请求体数据转换成对象
req.body = qs.parse(str);
console.log(req.body);
// 调用 next 函数,放行下一个中间件
next();
});
}
module.exports = bodyParser;
// 导入 express 模块
const express = require('express');
const app = express();
const bodyParser = require('./diy');
app.use(bodyParser);
app.post('/user', (req, res) => {
res.send(req.body);
})
// 启动服务器
app.listen(80, () => {
console.log('Server is running at http://localhost');
});
app.js
const express = require('express');
const app = express();
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
// 导入路由模块
const router = require("./router");
// 将路由模块挂载到 app 中
app.use(router);
app.listen(80, () => {
console.log('Server is running at http://localhost');
});
router.js
const express = require('express');
// 创建路由模块
const router = express.Router();
// get 请求
router.get('/user/list', (req, res) => {
// 获取客户端发送到服务器的数据
const query = req.query;
res.send({
status: 0,
msg: 'success',
data: query
});
});
// post 请求
router.post('/user/add', (req, res) => {
// 获取客户端发送到服务器的数据
const body = req.body;
res.send({
status: 0,
msg: 'success',
data: body
});
});
router.use(function (req, res, next) {
console.log("user");
next();
})
// 向外导出路由模块
module.exports = router
npm i cors
在路由之前配置 cors 解决接口跨域问题
const cors = require('cors')
app.use(cors())
Access-Control-Allow-Origin
res.setHeader('Access-Control-Allow-Origin','*') // 允许任何域请求
res.setHeader('Access-Control-Allow-Origin','www.xiaotao.cloud') // 允许指定域请求
Access-Control-Allow-Headers
默认情况下,CORS 仅支持客户端向服务器发送 9 个请求头
如果需要额外的请求头信息,则需要设置
res.setHeader('Access-Control-Allow-Headers', 'Content-Type, X-Custom-Header');
Access-Control-Allow-Methods
默认情况下 cors 仅支持 get post head
请求
// 只允许某些请求
res.setHeader('Access-Control-Allow-Methods', 'post, get, delete, put');
// 允许所有
res.setHeader('Access-Control-Allow-Methods', '*');
npm i mysql
const mysql = require('mysql');
// 建立与 mysql 的连接
const db = mysql.createPool({
host: '127.0.0.1',
user: 'root',
password: '123456',
database: 'blog'
});
// 查询所有
db.query(`SELECT * FROM blog_article`, (err, result) => {
if (err) console.log(err);
console.log(result);
});
// 添加
db.query(`INSERT INTO blog_tag VALUES ('java', 'http://www.xiaotao.cloud/java')`, (err, result) => {
if (err) console.log(err);
if (result.affectedRows > 0) {
console.log('添加成功');
} else {
console.log('添加失败');
}
});
// 添加 简写
const blog_tag = { tag_name : 'spring', tag_url : 'http://www.xiaotao.cloud/spring' };
db.query(`INSERT INTO blog_tag SET ?`, blog_tag, (err, result) => {
if (err) console.log(err);
if (result.affectedRows > 0) {
console.log('添加成功');
} else {
console.log('添加失败');
}
});
// 更新
db.query(`UPDATE blog_tag SET tag_name = 'JavaScript' WHERE tag_id = 1`, (err, result) => {
if (err) console.log(err);
if (result.affectedRows > 0) {
console.log('更新成功');
} else {
console.log('更新失败');
}
});
// 更新 简写
const blog_tags = { tag_id : 1, tag_name : 'spring', tag_url : 'http://www.xiaotao.cloud/spring' };
db.query(`UPDATE blog_tag SET ? WHERE tag_id = ?`, [blog_tags, tag_id], (err, result) => {
if (err) console.log(err);
if (result.affectedRows > 0) {
console.log('更新成功');
} else {
console.log('更新失败');
}
});
// 删除
db.query(`DELETE FROM blog_tag WHERE tag_id = 2`, (err, result) => {
if (err) console.log(err);
if (result.affectedRows > 0) {
console.log('删除成功');
} else {
console.log('删除失败');
}
});
安装
npm i jsonwebtoken express-jwt
jsonwebtoken
生成 jwt 字符串
express-jwt
将 jwt 字符串解析还原成 json 对象
const express = require('express');
const app = express();
// 导入 jwt 相关
const jwt = require('jsonwebtoken');
const expressJWT = require('express-jwt');
// 允许跨域
const cors = require('cors');
app.use(cors());
// 解析 post 表单数据中间件
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: false }));
// 定义 secret 密钥 用以生成 token 对 jwt 加密 解密
const secretKey = '123456 ^_^';
// 将 JWT 字符串解析还原成 JSON 对象的中间件 以 /api 访问的 不需要拦截
// 这里会自动添加一个 req.user 挂载用户信息
app.use(expressJWT({ secret: secretKey }).unless({ path: [/^\/api\//] }))
// 登录接口
app.post('/api/login', function (req, res) {
// 将 req.body 请求体中的数据,转存为 userinfo 常量
const userinfo = req.body
// 登录失败
if (userinfo.username !== 'admin' || userinfo.password !== 'root') {
return res.send({
status: 400,
message: '登录失败!',
})
}
// 登录成功
// 在登录成功之后,调用 jwt.sign() 方法生成 JWT 字符串。并通过 token 属性发送给客户端
// 参数1:用户的信息对象
// 参数2:加密的秘钥
// 参数3:配置对象,可以配置当前 token 的有效期
// 不要把密码加密到 token 字符中
const tokenStr = jwt.sign({ username: userinfo.username }, secretKey, { expiresIn: '30s' })
res.send({
status: 200,
message: '登录成功!',
token: tokenStr, // 要发送给客户端的 token 字符串
})
})
// 这是一个有权限的 API 接口
app.get('/admin/getinfo', function (req, res) {
// 使用 req.user 获取用户信息,并使用 data 属性将用户信息发送给客户端
console.log(req.user)
res.send({
status: 200,
message: '获取用户信息成功!',
data: req.user, // 要发送给客户端的用户信息
})
})
// 全局错误处理中间件,捕获解析 JWT 失败后产生的错误
app.use((err, req, res, next) => {
// 这次错误是由 token 解析失败导致的
if (err.name === 'UnauthorizedError') {
return res.send({
status: 401,
message: '无效的token',
})
}
res.send({
status: 500,
message: '未知的错误',
})
})
// 启动web服务器
app.listen(80, function () {
console.log('Express server running at http://127.0.0.1')
})