1、redis
1、 redis是内存数据库(mysql是硬盘数据库)
2、下载、安装、使用:
(1)官网下载即可;
(2)启动redis-server、redis-cli连接
3、 nodejs操作redis
/**
* @description 存储配置
* @author zrf
*/
let REDIS_CONF = {
port: 6379,
host: '127.0.0.1'
};
module.exports = {
REDIS_CONF
}
/**
* @description 连接redis的方法 get set
*/
const redis = require('redis');
const { REDIS_CONF } = require('../conf/db');
// 创建客户端
const redisClient = redis.createClient(REDIS_CONF.port, REDIS_CONF.host);
redisClient.on('error', err => {
console.error(err);
})
/**
*
* @param {string} key 键
* @param {string} val 值
* @param {number} timeout 过期时间,单位s
*/
function set(key, val, timeout = 60 * 60) {
if (typeof val === 'object') {
val = JSON.stringify(val);
}
redisClient.set(key, val);
redisClient.expire(key, timeout);
}
/**
*
* @param {string} key
*/
function get(key) {
const promise = new Promise((resolve, reject) => {
redisClient.get(key, (err, val) => {
if (err) {
reject(err);
return;
}
if (val == null) {
resolve(null);
return;
}
try {
resolve(JSON.parse(val));
} catch (ex) {
resolve(val);
}
})
})
return promise;
}
module.exports = {
set,
get
}
2、登录(cookie和session)
1、为何session使用用redis存储?
(1)session访问频繁,对性能要求极高
(2)session可不考虑断电丢失数据的问题
(3)session数据量不会太大(相比于mysql中存储的数据)
2、为何网站数据不适合用redis?
(1)操作频率不是太高(相比于session操作)
(2)断电不能丢失,必须保留
(3)数据量太大,内存成本太高
3、koa2配置session
// session配置
app.keys = ['UIsdf_7878#s'];
app.use(session({
key: 'weibo_sid', // cookie name
prefix: 'weibo:sess:', // redis key的前缀
cookie: {
path: '/',
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000 // 单位ms
},
store: redisStore({
all: `${REDIS_CONF.host}:${REDIS_CONF.port}`
})
}))
4、jest——单元测试
1、单元测试及其意义
(1)单个功能或接口,给定输入,得到输出。看输出是否符合要求;
(2)需手动编写用例代码,然后统一执行;
(3)意义:能一次性执行所有单测,短时间内验证所有功能是否正常;
2、使用jest
(1)*.test.js文件
(2)常用的断言
/**
* @description test demo
*/
function sum(a, b) {
return a + b;
}
test('test demo 1', () => {
const res = sum(10, 20);
expect(res).toBe(30);
})
(3)测试http接口
/**
* @description jest server
*/
const request = require('supertest');
const server = require('../src/app').callback();
module.exports = request(server);
/**
* @description json test
*/
const server = require("./server")
test('json 接口返回数据格式正确', async () => {
const res = await server.get('/json');
expect(res.body).toEqual({
title: 'koa2 json'
})
})
5、jwt
(1)jwt——json web token
(2)用户认证成功之后,server端返回一个加密的token给客户端
(3)客户端后续每次请求都带token,以示当前的用户身份
const Koa = require('koa')
const app = new Koa()
// jwt验证
const jwtKoa = require('koa-jwt');
const { SECRET } = require('./conf/constants');
// error han dler
onerror(app)
// jwt验证(客户端请求是否携带了token)
app.use(jwtKoa({
// secret解密(钥匙)
secret: SECRET
}).unless({
// 自定义哪些目录忽略jwt验证
path: [/^\/users\/login/]
}))
const router = require('koa-router')()
// 加密jsonwebtoken
const jwt = require('jsonwebtoken');
const util = require('util');
const { SECRET } = require('../conf/constants');
const verify = util.promisify(jwt.verify);
router.prefix('/users');
// 登录
router.post('/login', async (ctx, next) => {
const { username, password } = ctx.request.body;
let userInfo = null;
if (username === 'zhangsan' && password === 'abc') {
userInfo = {
userId: 1,
username: 'zhangsan',
nickname: '张三',
gender: 1
}
}
// 对用户信息进行加密
let token = null;
// 用户认证成功后,返回加密token给客户端
if (userInfo) {
token = jwt.sign(userInfo, SECRET, { expiresIn: '1h' });
}
if (userInfo == null) {
ctx.body = {
code: -1,
msg: '登录失败'
}
return;
}
ctx.body = {
code: 0,
data: token
}
})
// 获取用户信息
// 客户端请求携带token,jsonwebtoken解密,返回用户信息
router.get('/getUserInfo', async (ctx, next) => {
const token = ctx.request.header.authorization;
try {
const payload = await verify(token.split(' ')[1], SECRET);
ctx.body = {
code: 0,
userInfo: payload
}
} catch (err) {
ctx.body = {
code: -1,
errmsg: err.message
}
}
})
module.exports = router