node.js学习文档
1、fs文件系统模块
读取文件内容:fs.readFile()
//1、导入fs模块,来操作文件
const fs = require('fs')
//2、调用fs.readFile()方法读取文件
// 参数1:读取文件的存放路径
// 参数2:读取文件时候采用的编码格式,一般utf-8
// 参数3:回调函数,拿到读取失败和成功的结果 err dataStr
// 读取成功 err值为 null
// 读取失败 err值为错误对象,dataStr值为 undefined
fs.readFile('./file/1.txt','utf-8',function(err,dataStr){
if (err){
return console.log('读取文件失败'+ err.message)
}
console.log('成功读取到:' + dataStr)
})
写入文件内容:fs.writeFile()
//1、导入fs模块,来操作文件
const fs = require('fs')
//2、调用fs.writeFile方法写入文件
// 参数1:写入文件的存放路径
// 参数2:写入文件内容
// 参数3:写入文件时候采用的编码格式(可以省略该参数)
// 参数4:回调函数,写入失败和成功的结果 err
// 写入成功 err值为 null
var wtxt = '我要写入的内容文字'
fs.writeFile('./file/2.txt', wtxt, 'utf-8', function(err){
if (err){
return console.log('文件写入失败'+ err.message)
}
console.log('文件写入成功')
})
练习
//成绩.TXT 内容:小红=99 小白=100 小黄=70 小黑=66 小绿=88
const fs = require('fs')
fs.readFile('./file/成绩.txt','utf8',function(err,dataStr){
if(err){
return console.log('读取失败:'+err.message)
}
//console.log('读取文件成功:'+dataStr)
//.split把成绩数据分割,.filter去除多余空格
const arrOld = dataStr.split(' ').filter(item => item !== '')
//循环分割后的数组,对每一项数据就行字符串替换
const arrNew = []
arrOld.forEach(item => {
arrNew.push(item.replace('=',':'))
})
console.log(arrNew)
//现在是这样的
//[ '小红:99', '小白:100', '小黄:70', '小黑:66', '小绿:88' ]
//.join把新数组中的每一项进行合并
const newStr = arrNew.join('\r\n')
console.log(newStr)
//写入新的成绩-OK.txt
fs.writeFile('./file/成绩-OK.txt',newStr,function(err){
if(err){
return console.log('写入失败:'+err.message)
}
console.log('成功写入新的成绩')
})
})
//结果
//小红:99
//小白:100
//小黄:70
//小黑:66
//小绿:88
fs模块路径拼接的问题
//node命令时所处目录去动态拼接文件路径出现错误.
//__dirname表示当前文件所处的目录
console.log(__dirname)
const fs = require('fs')
fs.readFile(__dirname + '/file/1.txt','utf-8',function(err,dataStr){
if(err){
return console.log('文件读取错误'+err.message)
}
console.log('已经读取到文件:'+dataStr)
})
2、path路径模块
path.join拼接
const path = require('path')
const fs = require('fs')
//注意:../会抵消前面的路径
const pathStr = path.join('/a','/b/c','../','./d','e','rr')
console.log(pathStr)
//__dirname以后不要用+,用path.join拼接
fs.readFile(path.join(__dirname,'./file/1.txt'),'utf-8',function(err,dataStr){
if(err){
console.log("读取文件失败:"+err.message)
}
console.log('成功读取到文件:'+dataStr)
})
path.basename() 获取路径中的文件名
path.extname() 获取路径中的文件扩展名
const path = require('path')
//定义文件的存放路径
const fpath = './file/05.html'
const fullName = path.basename(fpath)
//显示:05.html
console.log(fullName)
//移除html后缀显示:05
const noHouZui = path.basename(fpath,'.html')
console.log(noHouZui)
//获取文件扩展名
const fext = path.extname(fpath)
console.log(fext)
//组合移除后缀扩展名字显示
const fpathFext = path.basename(fpath, fext)
console.log(fpathFext)
时钟案例
html原始代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>时钟案例</title>
<style>
body {
color: white;
font-family: Arial, sans-serif;
text-align: center;
background-image:-webkit-linear-gradient(60deg,rgba(218, 169, 215, 0.637),rgba(128, 174, 235, 0.904));
background-position: center 0;
background-repeat: no-repeat;
background-attachment: fixed;
background-size: cover;
-webkit-background-size: cover;
-o-background-size: cover;
-moz-background-size: cover;
-ms-background-size: cover;
}
#time {
margin:0 auto;
width:800px;
font-size: 5em;
border: 2px solid white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 20px white;
-webkit-box-reflect: below 0px -webkit-linear-gradient(top,rgba(255,0,0,0),rgba(255,0,0,1));
}
</style>
</head>
<body>
<h1>当前时间:</h1>
<p id="time"></p>
<script>
function updateTime() {
var now = new Date();
var hours = now.getHours();
var minutes = now.getMinutes();
var seconds = now.getSeconds();
if (seconds < 10) {
seconds = "0" + seconds;
}
var timeString = hours + ":" + minutes + ":" + seconds;
document.getElementById("time").innerHTML = timeString;
}
setInterval(updateTime, 1000);
</script>
</body>
</html>
nodejs代码
const fs = require('fs')
const path = require('path')
//定义正则表达式
const regStyle = /<style>[\s\S]*<\/style>/
const regScript = /<script>[\s\S]*<\/script>/
//调用fs.readFile()方法读取文件
fs.readFile(path.join(__dirname,'./file/time.html'),'utf-8',(err,dataStr)=>{
if(err){
return console.log("读取失败:" + err.message)
}
resolveCSS(dataStr)
resolveJS(dataStr)
resolveHTML(dataStr)
})
//定义处理css样式方法
function resolveCSS(htmlStr){
//使用正则提取需要的内容
const r1 = regStyle.exec(htmlStr)
const newCSS = r1[0].replace('<style>','').replace('</style>','')
fs.writeFile(path.join(__dirname,'./file/time.css'),newCSS,'utf-8',err=>{
if(err){
return console.log("写入CSS样式失败:" + err.message)
}
console.log("写入CSS样式成功")
})
}
//定义处理js脚本方法
function resolveJS(htmlStr){
const r2 = regScript.exec(htmlStr)
const newJS = r2[0].replace('<script>','').replace('</script>','')
fs.writeFile(path.join(__dirname,'./file/time.js'),newJS,'utf-8',err=>{
if(err){
return console.log("写入js文件错误:" + err.message)
}
console.log("写入JS文件成功")
})
}
//定义处理HTML结构方法
function resolveHTML(htmlStr){
const newHTML = htmlStr.replace(regStyle,'<link rel="stylesheet" href="./time.css">').replace(regScript,'<script src="./time.js"></script>')
fs.writeFile(path.join(__dirname,'./file/time_new.html'),newHTML,'utf-8',err=>{
if(err){
return console.log('写入html失败:' + err.message)
}
console.log('写入新的HTML文件成功')
})
}
3、web服务器http模块
//导入http模块
const http = require('http')
//创建web服务器实例
const server = http.createServer()
//为服务器实例绑定 request 事件,监听客户端的请求
server.on('request',(req,res)=>{
//req是请求对象,包含了与客户端相关的数据和属性
//req.url是客户端请求的URL地址
const url = req.url
//req.method是客户端请求的method类型
const method = req.method
const str = `你的请求URL地址是: ${url}\n请求的method类型为:${method}`
console.log(str)
//res.writeHead响应是一个 UTF-8 编码的文本,可以设置多个属性
res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'})
//res.setHeader响应是一个 UTF-8 编码的文本,只能设置一个属性
//res.setHeader('content-Type','text/html; charset=utf-8')
//setHeader 只能一个一个设置标头,writeHead可以一下设置很多
//setHeader 可以重复调用,writeHead只能调用一次
//同时出现setHeader和writeHead,setHeader会合并到writeHead,并且writeHead优先级高
//writeHead 可以设状态码和状态信息,setHeader不能设置,只能设置标头
//调用res.end()方法,向客户端响应一些内容
res.end(str)
})
//启动服务器
const port = 80
server.listen(port,()=>{
console.log(`服务器启动 http://127.0.0.1:${port}/\n服务器启动 http://localhost:${port}/`)
})
时钟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
//const fpath = path.join(__dirname,url)
let fpath = ''
if(url === '/'){
fpath = path.join(__dirname,'./file/time_new.html')
}else{
fpath = path.join(__dirname,'/file',url)
}
fs.readFile(fpath,'utf-8',(err,dataStr)=>{
if(err){
res.setHeader('content-Type','text/html; charset=utf-8')
return res.end('<h1>404 页面丢失,找不到了</h1>')
}
res.end(dataStr)
})
})
let port = 80
server.listen(port,()=>{
const ports = (port !== 80) ? ':'+ port : '';
console.log(`服务器启动 http://127.0.0.1${ports}/\n服务器启动 http://localhost${ports}/`)
})
4、自定义模块
自定义模块引入
//zdy.js可以简写zdy
const m = require('./file/zdy')
console.log(m)
自定义zdy.js
console.log('我就是自定义')
const age = 20
//module.exports对象挂载username属性
module.exports.username = 'xo'
//module.exports对象挂载sayHello方法
module.exports.sayHello = function(){
console.log('hello,xx')
}
module.exports.age = age
//让module.exports指向一个全新的对象,上面不再显示
module.exports = {
nickname:'小黑',
sayHi(){
console.log('Hi,Hi')
}
}
//exports = module.exports(优先)
5、Express使用
安装express
npm i express
创建基本Web服务器
//导入Express
const express = require('express')
//创建Web服务器
const app = express()
//监听客户端的GET和POST请求,并向客户端响应具体的内容
app.get('/user', (req, res)=>{
//向客户端响应一个JSON对象
res.send({name:'zs',age:20,gender:'男'})
})
app.post('/user',(req,res)=>{
//向客户端响应一个文本字符串
res.send('请求成功')
})
//获取URL中携带查询参数
app.get('/',(req,res)=>{
const squery = req.query
console.log(squery)
res.send(squery)
//传值http://127.0.0.1/?name=xu&age=20
})
//获取URL中的动态参数
//通过req.params对象可以访问到URL中:匹配到的动态参数
app.get('/user/:id&:name',(req,res)=>{
//reg.params默认一个空对象
//里面存放着通过:动态匹配到参数值
res.send(req.params)
console.log(req.params)
//获取值http://127.0.0.1/user/22&xu
})
//调用app.listen(端口号,启动成功回调函数),启动服务器
app.listen(80,()=>{
console.log('启动服务器 http://127.0.0.1')
})
托管静态资源
const express = require('express')
const app = express()
//调用express.static()方法,快速的对外提供静态资源
app.use(express.static('./file'))
//多次调用相同名称文件优先匹配第一个
app.use(express.static('./file2'))
//挂载路径前缀,前缀xo
app.use('/xo',express.static('./file'))
app.listen(80,()=>{
console.log('启动服务器 http://127.0.0.1')
})
使用nodemon
实现自动重启项目的效果
//安装nodemon
npm install -g nodemon
//使用nodemon
nodemon xxx.js
模块化路由
模块js
//新建routerModule/router_01.js
const express = require('express')
const router = express.Router()
//挂载具体路由
router.get('/xo',function(req,res){
res.send('Get一个路由')
})
router.post('/xo',(req,res)=>{
res.send('post一个路由')
})
//向外导出对象
module.exports = router
注册路由模块
const express = require('express')
const app = express()
//导入路由模块
const xoRouter = require('./routerModule/router_01')
//注册路由模块
app.use(xoRouter)
//使用app.use()注册路由模块统一添加访问前缀
app.use('/xx',xoRouter)
app.listen(80,()=>{
console.log('server runing at http://127.0.0.1')
})
中间件
全局生效中间件
const express = require('express')
const app = express()
//定义一个最简单的中间件函数
const mw = function(req,res,next){
console.log('这是个最简单的中间件函数')
const time = Date.now()
//为req对象挂载自定义属性,共享给后面所有路由
req.starxx = time
next()
}
//将mw注册为全局生效的中间件
app.use(mw)
//第二个简化中间件
app.use((req,res,next)=>{
console.log('这是调用第二个中间件的信息')
next()
})
app.get('/',(req,res)=>{
res.send('中间件页面' + req.starxx)
})
app.get('/www',(req,res)=>{
console.log('这个是WWW')
res.send('www中间件页面' + req.starxx)
})
app.listen(80,()=>{
console.log('server runing at http://127.0.0.1')
})
局部中间件
//不使用app.use()中间件都叫局部中间件
const express = require('express')
const app =express()
const mw01 = function(req,res,next){
console.log('这是第一个局部中间件')
next()
}
const mw02 = function(req,res,next){
console.log('这是第二个局部中间件')
next()
}
app.get('/',mw01,mw02,(req,res)=>{
res.send('访问到我这个局部中间件')
})
//中间件数组也是可以的
const mw = [mw01,mw02]
app.get('/www',mw,(req,res)=>{
res.send('访问www这个局部中间件')
})
app.listen(80,()=>{
console.log('server runing at http://127.0.0.1')
})
错误级别中间件
注意:错误中间件必须注册在所有路由之后
const express = require('express')
const app = express()
//定义错误的路由
app.get('/',(req,res)=>{
throw new Error('服务器内部发生错误')
res.send('我错了吗')
})
//错误级别的中间件捕获整个项目的异常错误,防止程序崩溃
app.use((err,req,res,next)=>{
console.log('错误信息:' + err.message)
res.send(err.message)
})
app.listen(80,()=>{
console.log('server runing at http://127.0.0.1')
})
内置中间件
const express = require('express')
const app = express()
//express.static()静态托管资源内置中间件
//http://127.0.0.1/xo/xxx.css
app.use('/xo',express.static('./file'))
//通过express.json()中间件解析表单中JSON格式的数据
app.use(express.json())
app.post('/user',(req,res)=>{
//通过req.body来获取JSON格式表单数据和url-encoded格式的数据
console.log(req.body)
res.send('ok')
})
//express.urlencoded()中间件解析url-encoded格式的数据
app.use(express.urlencoded({ extended: false}))
app.post('/book',(req,res)=>{
console.log(req.body)
res.send('ok')
})
app.listen(80,()=>{
console.log('server runing at http://127.0.0.1')
})
自定义中间件
const express = require('express')
const app = express()
//querystring模块解析请求体数据
const qs = require('querystring')
app.use((req,res,next)=>{
//定义str字符串存储客户端发送过来的请求数据
let str = ''
//监听req的data事件
req.on('data',(chunk)=>{
str += chunk
})
//监听req的end事件
req.on('end',()=>{
//在str中存放完整请求体数据
// console.log(str)
const body = qs.parse(str)
//解析出来数据挂载为req.body
req.body = body
next()
})
})
app.post('/user',(req,res)=>{
res.send(req.body)
})
app.listen(80,()=>{
console.log('server runing at http://127.0.0.1')
})
自定义中间件拆分封装模块
模块地址./custom-body-parser/01.js
const qs = require('querystring')
const bodyParser = (req,res,next)=>{
//定义str字符串存储客户端发送过来的请求数据
let str = ''
//监听req的data事件
req.on('data',(chunk)=>{
str += chunk
})
//监听req的end事件
req.on('end',()=>{
//在str中存放完整请求体数据
// console.log(str)
const body = qs.parse(str)
//解析出来数据挂载为req.body
req.body = body
next()
})
}
module.exports = bodyParser
引入自定义封装模块
const express = require('express')
const app = express()
//导入自己封装的中间件模块
const customBodyParser = require('./custom-body-parser/01')
//注册
app.use(customBodyParser)
app.post('/user',(req,res)=>{
res.send(req.body)
})
app.listen(80,()=>{
console.log('server runing at http://127.0.0.1')
})
编写接口
新建routerModule/apiRoyter.js
const express = require('express')
const router = express.Router()
router.get('/get',(req,res)=>{
//通过req.query获取客户端通过查询字符串,发送到服务器的数据
const query = req.query
res.send({
status: 0,//0表示处理成功,1表示处理失败
msg:'get请求成功',//状态描述
data:query //需要响应给客户端的数据
})
})
router.post('/post',(req,res)=>{
//请求包含urlcoded格式一定匹配express.urlencoded()中间件解析
const body = req.body
res.send({
status: 0,
msg:'Post请求成功',
data: body
})
})
module.exports = router
引入apiRoyter.js路由接口模块
const express = require('express')
const app = express()
////express.urlencoded()中间件解析url-encoded格式的数据
app.use(express.urlencoded({extended:false}))
const router = require('./routerModule/apiRoyter')
app.use('/api',router)
app.listen(80,()=>{
console.log('server runing at http://127.0.0.1')
})
//访问http://127.0.0.1/api/get
//访问http://127.0.0.1/api/post
cors中间件解决跨域问题
安装并使用cors
//安装cors
npm i cors
//导入中间件
const cors = require('cors')
//在路由之前调用配置注册中间件
app.use(cors())
第二种是直接在路由中输入cors响应头部
//只允许来自xx.com域的请求
res.setHeader('Access-Control-Allow-Origin','http://hwoo.com')
//只允许Post、Get、Delete、Head请求方法
res.setHeader('Access-Control-Allow-Methods','POST,GET,DELETE,HEAD')
//额外请求头信息进行声明
res.setHeader('Access-Control-Allow-Headers','content-Type,x-Custom-Header')
第三种是用app.all解决,比起第二种更加全面 包含了不同请求格式
app.all('*', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header('Access-Control-Allow-Headers', ['mytoken','Content-Type']);
next();
});
6、mysql使用
基础使用语句
--选择查询
select * from xx表
--选择查询表字段和AS别名
select name as "姓名" ,age from xx表
--添加一条数据
insert into xx表 (name,age) values('xx',20)
--修改数据 where是判断条件
update xx表 set name = 'yy' where id=970
--删除数据
delete from xx表 where id=970
--排序order by默认升序asc
select * from xx表 order by id
select * from xx表 order by id asc
--降序desc
select * from xx表 order by id desc
--多重排序
select * from xx表 order by id desc, name asc
--count(*)查询结果总数居条数
select count(*) fron xx表
安装mysql模块
npm install mysql
配置数据库
const mysql = require('mysql')
const db = mysql.createPool({
host:'127.0.0.1',
port:'3306',
user:'root',
password:'xxxxx',
database:'myt_online',
})
//查询语句
const sqlSelect ="select count(*) as '统计数' from customer"
db.query(sqlSelect,(err,results)=>{
if(err){
return console.log('数据库连接错误:' + err.message)
}
console.log(results)
})
插入、更新、删除数据
const mysql = require('mysql')
const db = mysql.createPool({
host:'127.0.0.1',
port:'3306',
user:'root',
password:'xxxxx',
database:'myt_online',
})
const user = {name:'旭达',age:20}
const sqlAdd = 'insert into customer (name,age) values(?, ?)'
db.query(sqlAdd,[user.name,user.age],(err,results)=>{
if(err){
return console.log('数据库连接错误:' + err.message)
}
//使用插入数值时候 .affectedRows判断插入成功
if(results.affectedRows === 1){
console.log('插入数据成功')
}
})
//便捷的插入数据方法
const user = {name:'旭达',age:20}
const sqlAdd = 'insert into customer set ?'
db.query(sqlAdd,user,(err,results)=>{
if(err){
return console.log('数据库连接错误:' + err.message)
}
//使用插入数值时候 .affectedRows判断插入成功
if(results.affectedRows === 1){
console.log('插入数据成功')
}
})
7、身份认证
session使用
//安装session
npm install express-session
配置session
const express = require('express')
const app = express()
//配置session中间件
const session = require('express-session')
app.use(
session({
secret: 'xxoxx', //任意加密字符串
resave: false, //固定写法
saveUninitialized: true, //固定写法
})
)
// 托管静态页面
app.use(express.static('./session_page'))
// 解析 POST 提交过来的表单数据
app.use(express.urlencoded({ extended: false }))
// 登录的 API 接口
app.post('/api/login',(req,res)=>{
if(req.body.username !== 'admin' || req.body.password !=='123456'){
return res.send({status: 1, msg: '登录失败'})
}
//登录成功后生成用户信息,保存到session中
req.session.user = req.body // 用户的信息
req.session.islogin = true // 用户的登录状态
res.send({status: 0, msg: '登录成功'})
})
//获取用户姓名的接口
app.get('/api/username',(req,res)=>{
if(!req.session.islogin){
return res.send({status: 1, msg: 'fail'})
}
res.send({
status: 0,
msg: 'success',
username: req.session.user.username,
})
})
//退出登录清空session信息
app.post('/api/logout',(req,res)=>{
req.session.destroy()//清空session
res.send({
status: 0,
msg: '退出登录成功'
})
})
app.listen(80,()=>{
console.log('server runing at http://127.0.0.1')
})
index.html
<body>
<h1>首页</h1>
<h2 id="welcome"></h2>
<button id="btnLogout">退出登录</button>
<script>
$(function () {
// 页面加载完成后,自动发起请求,获取用户姓名
$.get('/api/username', function (res) {
// status 为 0 表示获取用户名称成功;否则表示获取用户名称失败!
if (res.status !== 0) {
alert('您尚未登录,请登录后再执行此操作!')
location.href = './login.html'
} else {
//alert('欢迎您:' + res.username)
$('#welcome').html('登录姓名:'+res.username);
}
})
// 点击按钮退出登录
$('#btnLogout').on('click', function () {
// 发起 POST 请求,退出登录
$.post('/api/logout', function (res) {
if (res.status === 0) {
// 如果 status 为 0,则表示退出成功,重新跳转到登录页面
location.href = './login.html'
}
})
})
})
</script>
</body>
login.html
<body>
<!-- 登录表单 -->
<form id="form1">
<div>账号:<input type="text" name="username" autocomplete="off" /></div>
<div>密码:<input type="password" name="password" /></div>
<button>登录</button>
</form>
<script>
$(function () {
// 监听表单的提交事件
$('#form1').on('submit', function (e) {
// 阻止默认提交行为
e.preventDefault()
// 发起 POST 登录请求
$.post('/api/login', $(this).serialize(), function (res) {
// status 为 0 表示登录成功;否则表示登录失败!
if (res.status === 0) {
location.href = './index.html'
} else {
alert('登录失败!')
}
})
})
})
</script>
</body>
token的使用
//安装JWT相关的包
npm install jsonwebtoken express-jwt
//jsonwebtoken用于生成JWT字符串
//express-jwt用于将JWT字符串解析还原成json对象
定义secret密钥
const secretKey = 'xxyy oo mm ^_^'
案例
const express = require('express')
const app = express()
// TODO_01:安装并导入 JWT 相关的两个包,分别是 jsonwebtoken 和 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 }))
// TODO_02:定义 secret 密钥,建议将密钥命名为 secretKey
const secretKey = 'xxyy oo mm ^_^'
// TODO_04:注册将 JWT 字符串解析还原成 JSON 对象的中间件
// 注意:只要配置成功了 express-jwt 这个中间件,就可以把解析出来的用户信息,挂载到 req.user 属性上
//最新版本需要配置algorithms算法,一般默认是HS256
app.use(expressJWT.expressjwt({ secret: secretKey, algorithms: ["HS256"] }).unless({
path: [/^\/api\//],
}))
// 登录接口
app.post('/api/login', function (req, res) {
// 将 req.body 请求体中的数据,转存为 userinfo 常量
const userinfo = req.body
// 登录失败
if (userinfo.username !== 'admin' || userinfo.password !== '000000') {
return res.send({
status: 400,
message: '登录失败!',
})
}
// 登录成功
// TODO_03:在登录成功之后,调用 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) {
// TODO_05:使用 req.user 获取用户信息,并使用 data 属性将用户信息发送给客户端
console.log(req.auth)
res.send({
status: 200,
message: '获取用户信息成功!',
data: req.auth, // 要发送给客户端的用户信息
})
})
// TODO_06:使用全局错误处理中间件,捕获解析 JWT 失败后产生的错误
app.use((err, req, res, next) => {
// 这次错误是由 token 解析失败导致的
if (err.name === 'UnauthorizedError') {
return res.send({
status: 401,
message: '无效的token',
})
}
res.send({
status: 500,
message: '未知的错误',
})
})
// 调用 app.listen 方法,指定端口号并启动web服务器
app.listen(8888, function () {
console.log('Express server running at http://127.0.0.1:8888')
})