首页 > 数据库 >nuxt 添加 redis 缓存

nuxt 添加 redis 缓存

时间:2024-12-30 13:21:17浏览次数:1  
标签:缓存 const res redis js key nuxt

这个文章的主要目的是通过 redis 缓存 nuxt2 中服务端渲染的页面。从而优化加载速度以及减轻服务端的压力。

Nuxt

是什么

Nuxt.js 是一个基于 Vue.js 的开源框架,旨在为开发者提供一个简单的方式来构建高性能的 Vue 应用。它提供了许多功能,使得开发服务器端渲染(SSR)、静态站点生成(SSG)和单页面应用(SPA)变得更加容易。nuxt2官网nuxt3的地址

Redis

是什么

Redis 是一个开源的内存数据结构存储系统,广泛用于数据库、缓存和消息代理。它支持多种数据结构,如字符串、哈希、列表、集合和有序集合。它具有高性能的特性,可以处理每秒数百万个请求,具有极高的读写性能。通常会被我们使用在缓存的存储中,提高应用程序的响应速度。Redis的官网

前期准备

首先我们本地开发的时候,本地要先安转 redis。下载后,终端运行 redis-server 既可开启 Redis 服务。开启后终端中就能看到这个图标。

# 开启 redis-server
redis-server
# 打开 redis cli
redis-cli

Nuxt 通过 Redis 添加缓存

开始

首先我们要有一个 nuxt 项目,这里我新建一个项目,如果原先有项目,也可以直接在原项目中进行。通过官方文档,建立一个新的项目。

# npm
npm init nuxt-app nuxt2

然后就是下载依赖,选择所需框架。最后 cd nuxt2 ,执行 npm run dev 跑起来。

下载 Node Redis

npm install redis@3

这里我们下载 redis npm 包,我们这里用的nuxt2,所以这里指定版本下载的是 redis@3redis@3 的文档可以看这个(https://www.npmjs.com/package/redis/v/3.1.2)。

在根目录下创建一个 cache 目录文件,用来存储 redis 相关配置。

// cache > index.js
const redis = require('redis')

const client = redis.createClient(6379, '127.0.0.1')

client.on('error', function(error) {
  console.error('redis error:', error)
})

// 封装 get、set
function getRedis(key, callback) {
	client.get(key, callback)
}

function setRedis(key, value, timeout = 60*60) {
	client.set(key, value, redis.print)
  // 设置超时时间
  client.expire(key, timeout)
}

export {
	getRedis,
	setRedis
}

通过 redis 的文档可以看到,get [key] 的时候会传进一个回调函数,用来获取错误信息或对应的 value

redis@3 目前不支持原生 Promise,这一个功能会在 v4 版本中推出。但是文档中给出了包装成 promise 的方法,利用的是 util.promisify 方法。具体的文档位置

// 文档中的 promise 包装例子
const { promisify } = require('util')
const getAsync = promisify(client.get).bind(client)

getAsync.then(console.log).catch(console.error)

在进行下一步之前,我们可以将 redis 的相关配置提取出来,可以在 cache 中创建一个 _config.js 文件,用来存储配置相关。而 redis.createClient 方法的相关配置,可以查看文档位置

// cache > _config.js
let redisConfig = {
  post: 6379,
  host: '127.0.0.1'
}

// production 判断,redisConfig = { ... }

module.exports = {
  redisConfig
}

index 中修改

const { redisConfig } = require('./_config')

// 修改部分
// - const client = redis.createClient(6379, '127.0.0.1')
const client = redis.createClient(redisConfig.post, redisConfig.host)

写中间件

redis 相关封装完毕后,我们就可以来写中间件了。首先在根目录创建 middleware 文件夹,用来存储所有的中间件。在 nuxt 中,中间件有 middlewareserverMiddleware 。他们是两个完全不同的概念。

middleware

middleware 一般用于 页面 与 路由 之间执行的函数,可以用来处理用户请求前的逻辑。一般用来进行 身份验证、用户权限判断、重定向用户、数据预处理等 。适用于 客户端 与 服务端。

serverMiddleware

serverMiddleware 则是用于服务器端运行的中间件,用来处理 HTTP 请求。所以他用来 处理 API 请求、处理文件上传、或者是其他自定义的服务器逻辑。他运行在服务器接收到请求时执行。

两者的写法

// middleware
export default function ({ store, redirect }) {
  // ...
}

// serverMiddleware
export default function (req, res, next) {
	// ...
  next()
}

cache 中间件

我们来写 cache 中间件,在 middleware 文件夹中创建一个 cache.js 文件。

这里为了区别 serverMiddleware 和 middleware。可以在 middleware 中创建 server,然后在 server 中创建 cache.js。也有在根目录中创建 server > middleware > [servermiddleware].js 的。都是可以的。

// middleware > cache.js
import { getRedis, setRedis } from '../cache'

export default function (req, res, next) {
  const reg = /.(js|css|png|json)$/g
  const useCache = !reg.test(req.url)
  
  if (useCache) {
    const redisKey = `PN:PAGE:${req.url}`
    getRedis(redisKey, function(err, val) {
      if (err) next()
      else cacheMain(redisKey, val, req, res, next)
    })
  } else {
    next()
  }
}

function cacheMain(key, val, req, res, next) {
  if (val) {
    // 有缓存
    res.end(val, 'utf-8')
  } else {
   	// 没有缓存,存缓存,并且返回
    res.origin_end = res.end
    res.end = (data) => {
      if (res.statusCode === 200) {
        // 写入
        setRedis(key, data)
      }
    }
    res.origin_end(data, 'utf-8')
  }
  next()
}

然后我们在 nuxt.config.js中配置 serverMiddleware

// nuxt.config.js
export default {
  // ... 其他配置
  
  serverMiddleware: [
    '~/middleware/cache.js'
  ]
}

验证

这时我们在浏览器访问 localhost:3000,然后在终端 redis-cli 中查看 keys *,可以看到已经存在相关数据。get [key],即可得到我们的页面数据。

keys *
get [key]

这里我们也可以创建多个页面进行验证,在 pages 目录下创建一个 m.vue 文件,浏览器再访问 location:3000/m

<!-- pages > m.vue -->
<template>
	<div>
    <p style="color: blue;">移动端页面</p>
  </div>
</template>

这时我们可以看到 keys * 中有两条数据。

超时检测,这个可以调小 timeout ,比如设置成 60s 来进行测试。

至此,我们已经完成了对页面的缓存。

缓存优化

存储内容

目前我们存储在 redis 中的页面数据是整个 html 文件。当前我初始化的项目的页面内容比较少,但是如果是一个正式上线的项目,页面渲染的内容就不一定是简单的内容展示了。所以这里我们来对缓存内容进行优化,缓存前进行压缩,读取后进行解压处理。

数据压缩和解压的库这里我选择用 zlib,他对比与 pako,更适用于服务器端。

# 安装 zlib
npm i zlib

下载完后再 cache 目录下创建 zlib.js 文件,首先我们先写一段代码测试下 zlib 的压缩和解压功能。

const zlib = require('zlib')
const str = 'hello, zlib'

let compressData
zlib.deflate(Buffer.from(str), (err, end) => {
  console.log(err, end.toString('base64'), 'deflate')
  compressData = end.toString('base64')
})

setTimeout(() => {
  zlib.inflate(Buffer.from(compressData, 'base64'), (err, data) => {
    console.log(err, data.toString(), 'inflate')
  })
}, 1000)

测试可以看出加压和解压的功能是可行的,接下来就是对加压和解压功能做封装处理。

// cache > zlib.js
const zlib = require('zlib')

/**
 * 压缩
 * @param {*} string
 */
function compress(string) {
  return new Promise((resolve, reject) => {
    const buffer = Buffer.from(string)
    zlib.deflate(buffer, (err, compressData) => {
      if (err) { reject(err) }
      else {
        resolve(compressData.toString('base64'))
      }
    })
  })
}

/**
 * 解压
 * @param {*} compressData
 */
function decompress(compressData) {
  return new Promise((resolve, reject) => {
    const buffer = Buffer.from(compressData, 'base64')
    zlib.inflate(buffer, (err, decompressData) => {
      if (err) { reject(err) }
      else {
        resolve(decompressData.toString())
      }
    })
  })
}

export {
  compress,
  decompress
}

同时 middleware 中的 cache.js 要引入并使用相关方法。

// middleware > cache.js
import { compress, decompress } from "../cache/zlib"

function cacheMain(val, key, req, res, next) {
  if (val) {
    // 有缓存,直接获取缓存数据
    decompress(val).then(decompressRes => {
      res.end(decompressRes, 'utf-8')
    }).catch(err => {
      console.error(err)
    })
  } else {
    // 没有缓存,通过 res.end 获取页面数据
    res.original_end = res.end
    res.end = (data) => {
      if (res.statusCode === 200) {
        // 修改位置
        setRedisCache(key, data)
      }
      res.original_end(data, 'utf-8')
  }
}
  
function setRedisCache(key, data) {
  // setRedis(key, data)
  compress(data).then(res => {
    setRedis(key, res)
  }).catch(() => {
    // 压缩失败
    return false
  })
}

配置完上面的数据,我们重新运行可以项目是可以正常运行的,页面也没有异常。我们的验证重心要放在 redis 中存储的数据。在进行验证之前,我们先查看一下当前存储的页面数据大小。通过 memory usage [key] 查看。我本地的 / 页的大小是:

随后我们进行数据压缩存储,通过 get [key] 可以看出,redis 中存储的数据已经变成了 base64 格式。同时我们查看数据大小也已经发生了改变。

缓存时间

完成页面内容压缩后,我们再从缓存时间来找一下优化点。目前项目中的页面都是统一缓存时间。但是页面被访问的次数并不一定是一致的。有时我们就想,如果在页面缓存过期时间内,页面被多次访问,或到达一定的访问次数,页面缓存过期时间就跟着叠加。这个功能实现起来不难,主要是我们要去记录这个访问次数以及如何去记录这个访问次数。

目前我们 redis 中记录的内容是压缩后的 page 内容。我们可以修改这个存储内容,将存储信息变成一个对象,里面存储着访问次数,page 内容等。

const needCacheData = {
  content: pageData,
  accessCount: 1
}

然后存储的时候压缩 JSON.stringify(needCacheData),取值的时候获取 needCacheData.content,访问次数则是 accessCount。

// middleware > cache.js
function cacheMain(val, key, req, res, next) {
  if (val) {
    decompress(val).then(decompressRes => {
			// 修改位置,这里的 decompressRes 不是 pageContent 了,而是 { accessCount, content }
      const cacheData = JSON.parse(decompressRes)
      if (cacheData.accessCount === 1) {
        // 更新缓存
        cacheData.accessCount++
        setRedisCache(key, cacheData)
      }
      
      res.end(cacheData.content)
    })
  } else {
    // ... 其他代码
    // 修改部分
    res.end = (data) => {
			// 写入缓存前初始化缓存数据
      const cacheData = {
        accessCount: 1,
        content: data
      }
      setRedisCache(key, cacheData)
    }
  }
}

// setRedisCache 第二个参数改成 obj
function setRedisCache(key, obj) {
  // 初始化
  let expire = 60 * 60
  if (data.accessCount !== 1) {
    expire = 24 * 60 * 60
  }
  
  compress(JSON.stringify(data)).then(res => {
    setRedis(key, res, expire)
  }).catch(err => {
    // ...
  })
}

这里的 expire 超时可以按照自己的需求设置。例如 accessCount 次数到达多少次后再加长时间等。至于验证的话,第一次访问的时候,可以通过 TTL [key] 查看当前时间,二次访问后再看过期时间。

标签:缓存,const,res,redis,js,key,nuxt
From: https://www.cnblogs.com/limoonrise/p/18640801

相关文章

  • 记录:wsl2 安装 CentOS8-stream 安装docker 安装redis-cluster集群 一些步骤及问题
     一。解压  下载的CentOS8-stream.zip压缩包,双击安装   (下载地址记录:wsl2安装centOS7一些问题解决并使用shell工具连接)  二。修改root密码 (安装后直接进入root 不知道密码所以修改)  直接passwd即可修改   三。yumli......
  • redis-2(集群模式)
    主从模式(master-slave)实战规划图实际配置1,克隆主机,以redis1为基础,克隆出redis2和32,配置IP和主机名称,重启,使用xshell链接vi/etc/sysconfig/network-scripts/ifcfg-ens33:1521->22vi/etc/hostname:1redis2reboot重启使用xshell或者finalShell链接......
  • redis-3
    缓存流程图缓存实战准备工作复制项目,修改名称引入jar包<!--springboot整合redisjar开始--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><depende......
  • redis-1
    nosqlcpu,内存和磁盘的关系nosql简介NoSQL(notonlysql),泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在处理web2.0网站,特别是超大规模(京东,淘宝,天猫.......)和高并发的SNS(社交平台)类型的web2.0纯动态网站已经显得力不从心(基于磁盘存储),出现了很多难以克服......
  • 2024-12-25《linux上安装redis报错》
     在linux上安装redis时,首先要安装c/c++编译器,然后安装redis,不然redis跑不了,安装时报错:cdsrc&&makeallmake[1]:Enteringdirectory'/opt/redis-7.0.0/src'CCMakefile.depCCserver.oInfileincludedfromserver.c:30:server.h:57:10:fatalerror:systemd......
  • 本地更新正常但上传空间后无法更新缓存
    当您在本地环境中能够顺利地更新网站后台并保存更改,但在上传至虚拟主机后却遇到了无法更新缓存的问题时,这通常意味着存在某些配置差异或环境兼容性问题。以下是一些常见的原因及解决方案,帮助您更好地理解和处理这种情况:服务器环境差异:PHP版本不匹配:不同服务器可能运行着不同......
  • [4427] 13 缓存优化:那些基于缓存的优化方案
    上节课的思考题是Webpack4中TreeShaking的触发条件有哪些?我们一起来回忆一下,要让引入的模块支持TreeShaking,一般有4点需要注意:引入的模块需要是ES6类型的,CommonJS类型的则不支持。引入方式不能使用default。引用第三方依赖包的情况下,对应的package.json......
  • 腾讯音乐:说说Redis脑裂问题?
    Redis脑裂问题是指,在Redis哨兵模式或集群模式中,由于网络原因,导致主节点(Master)与哨兵(Sentinel)和从节点(Slave)的通讯中断,此时哨兵就会误以为主节点已宕机,就会在从节点中选举出一个新的主节点,此时Redis的集群中就出现了两个主节点的问题,就是Redis脑裂问题。脑裂问题影响......
  • linux中,redis哨兵和数据持久化存储
    redis哨兵:"主从同步增强架构","读写分离","高可用" 1.概念 是Redis主从同步的增强架构,可以实现Redis主从同步的读写分离和高可用 2.特性: 1、可以承接客户端连接,但不存储数据 2、实现Redis主从复制组的监控 3、实现Redis主从的读写分离 4、Redis主从复制组的故......
  • Redis-十大数据类型
    Reids数据类型指的是value的类型,key都是字符串redis-server:启动redis服务redis-cli:进入redis交互式终端常用的key的操作redis的命令和参数不区分大小写,key和value区分1、查看当前库所有的keykeys*2、判断某个key是否存在existskey3、查看key是什么类型......