一、node.js 连接 redis
1、配置 REDIS_CONF
在 .conf/db.js 文件中添加 redis 配置,类似于 mysql 的配置
// 获取环境参数,process 为 node.js 进程的一些信息 const env = process.env.NODE_ENV // 配置 let MYSQL_CONF let REDIS_CONF // 开发环境下 if (env === 'dev') { // mysql 配置 MYSQL_CONF = { host: 'localhost', user: 'root', password: '1234abcd', port: '3306', database: 'myblog' } // redis 配置 REDIS_CONF = { port: 6379, host: '127.0.0.1' } } // 线上环境下 if (env === 'production') { // mysql 配置 MYSQL_CONF = { host: 'localhost', user: 'root', password: '1234abcd', port: '3306', database: 'myblog' } // redis 配置 REDIS_CONF = { port: 6379, host: '127.0.0.1' } } // 导出共享 module.exports = { MYSQL_CONF, REDIS_CONF }
2、更改 redis 版本
之后我们在 ./db/redis.js 文件中进行设置(在上篇文章的测试基础上做了一些修改)
由于使用最新版 redis 有一些变动的问题,在这里我们卸载之前的版本,转为使用 3.x 版本
npm uninstall redis
npm i redis@3.1.2
const redis = require('redis') const { REDIS_CONF } = require('../conf/db.js') // 创建客户端 const redisClient = redis.createClient(REDIS_CONF.port, REDIS_CONF.host) redisClient.on('error', err => { console.error(err) }) function set(key, val) { // 是对象的话转为 JSON 字符串的格式 if (typeof val === 'object') { val = JSON.stringify(val) } redisClient.set(key, val, redis.print) } function get(key) { const promise = new Promise((resolve, reject) => { redisClient.get(key, (err, val) => { // 出错 if (err) { reject(err) return } // val 为 null,给它返回 null if (val == null) { resolve(null) return } try { // 先尝试作为对象返回 resolve( JSON.parse(val) ) } catch (ex) { // 上面不成功的话直接返回 resolve(val) } }) }) return promise } module.exports = { set, get }
3、redis 解析 session
之后我们删掉 app.js 中解析 session 的代码(因为我们要使用 redis 解析 session)
// session 数据 // const SESSION_DATA = {} ...... // 解析 session // let needSetCookie = false // let userId = req.cookie.userid // if (userId) { // if (!SESSION_DATA[userId]) { // SESSION_DATA[userId] = {} // } // } else { // needSetCookie = true // userId = `${Date.now()}_${Math.random()}}` // SESSION_DATA[userId] = {} // } // req.session = SESSION_DATA[userId]
我们使用 redis 来解析 session,修改 app.js 的代码如下:
// 引入 get set const { get, set } = require('./src/db/redis') ...... // 解析 session (使用 redis) let needSetCookie = false let userId = req.cookie.userid // 没有 userId 则需要 cookie if (!userId) { needSetCookie = true userId = `${Date.now()}_${Math.random()}` // 初始化 redis 中的 session 值为一个空对象 set(userId, {}) } // 获取 session req.sessionId = userId get(req.sessionId).then(sessionData => { if (sessionData == null) { // 初始化 redis 中的 session 值 set(req.sessionId, {}) // 设置 session 为空对象 req.session = {} } else { // session 不为空,直接赋值 req.session = sessionData } console.log('req.session', req.session) // 处理 post data return getPostData(req) }) ......
4、session 同步到 redis
接下来,我们修改 .router/user.js 文件里面的内容,让 session 同步到 redis
const { set } = require('../db/redis') ...... // 登录 if (method === 'GET' && req.path === '/api/user/login') { // const { username, password } = req.body const { username, password } = req.query // 传入两个参数 用户名 密码 const result = login(username, password) return result.then(data => { if (data.username) { // 操作 cookie;path=/:保证所有路径都能用;httpOnly:只允许后端来改;expires:设置过期时间 // res.setHeader('Set-Cookie', `username=${data.username}; path=/; httpOnly; expires=${getCookieExpires()}`) // 设置 session req.session.username = data.username req.session.realname = data.realname // session 同步到 redis set(req.sessionId, req.session) console.log('req.session is', req.session) return new SuccessModel() } return new ErrorModel('登录失败') }) }
此时,我们进行登录测试
尝试登录——>登录成功
之后再次进行登录测试
二、server 端登录代码
在 ./router/blog.js 文件中,编写统一登录验证函数
const loginCheck = (req) => { // 没有登录 if (!req.session.username) { return Promise.resolve( new ErrorModel('尚未登录') ) } }
在新建博客、更新博客和删除博客的 if 判断中加入以下代码:
// 调用统一登录验证函数 const loginCheckResult = loginCheck(req) if (loginCheckResult) { // 未登录 return loginCheck }
更改新建博客和删除博客的 author,不再使用假数据
const author = req.session.username
在 .router/user.js 文件中,删除登录验证测试的代码,更改登录请求为PPOST类型
// 登录 if (method === 'POST' && req.path === '/api/user/login') { const { username, password } = req.body // const { username, password } = req.query ...... }
查看当前list
三、写在最后
至此,我们完成了cookie,session 和 redis 的对接(它们各司其职)。继续跟进学习吧!
后续会对该项目进行多次重构【多种框架(express,koa)和数据库(mysql,sequelize,mongodb)】