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')
})

游荡时间:
到此一游: xoxu, 大荣