Skip to content

Commit

Permalink
添加http缓存代码示例
Browse files Browse the repository at this point in the history
  • Loading branch information
onresize committed Apr 20, 2024
1 parent bfef76b commit 4230648
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 9 deletions.
Binary file added docs/.vuepress/public/AA_mdPics/hello.min.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/.vuepress/public/AA_mdPics/request.min.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/.vuepress/public/AA_mdPics/response.min.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
172 changes: 163 additions & 9 deletions docs/技术总结/踩坑总结/http缓存.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,27 @@ description: http缓存
# http缓存

> 本文作者:[onresize](https://github.com/onresize)
- ### 请求头
<p align="left">
<img src="/AA_mdPics/request.min.png" />
</p>

- ### 响应头
<p align="left">
<img src="/AA_mdPics/response.min.png" />
</p>

:::tip
注:http缓存只针对 get 请求、对其他请求无效
:::
- web缓存主要包括两部分:`浏览器缓存``http缓存`

- 浏览器缓存:`localStorage(<5M), sessionStorage(<5M), cookie(<4kb)`、本文重点是http缓存
- http缓存分为两种:`强缓存``协商缓存`

[node代码示例](https://gitee.com/onresize/koa-node)

### `1.强缓存`
- 直接从内存或磁盘中读取目标资源、无需和服务器通讯
- #### 1.1.基于 `Expires` 字段实现的强缓存
Expand All @@ -24,13 +40,33 @@ description: http缓存
- 对于强缓存来说、Expires 已经不是实现强缓存的首选、因为 Expires 判断是否过期是通过设置的时间和本地时间作比较、如果本地改变时区那时间就不准确了、这样就可能出现资源无法被缓存活永远被缓存的情况
- #### 1.2.强缓存首选:`cache-control` 字段代替 `Expires` 字段、`Cache-control` 这个字段在http1.1中被增加
- `Cache-control` 的使用方法页很简单,只要在资源的响应头上写上需要缓存多久就好了,单位是秒。例:
<br >

koa服务设置强缓存
```js
router.get('/getCaptcha', async (ctx) => {
ctx.set('Cache-Control', 'max-age=10') // max-age=10表示 10s 之内请求都走缓存
})
```

express服务设置强缓存
```js
//往响应头中写入需要缓存的时间
res.writeHead(200,{
'Cache-Control':'max-age=10'
});
router.get('/getCaptcha', (req, res) => {
res.writeHead(200, {
'Cache-Control':'max-age=10'
});
})
```

http服务设置强缓存
```js
let server = http.createServer((req, res) => {
res.setHeader('Cache-Control', 'public, max-age=86400')
// or
// res.writeHead(200, { 'Cache-Control': 'max-age=100' })
})
```

<p align="center">
<img src="/AA_mdPics/hc1.png" />
</p>
Expand All @@ -52,17 +88,135 @@ res.writeHead(200,{

### `2.协商缓存`

- 2.1.基于 `last-modified` 的协商缓存实现方式是:
```js
- 2.1.基于 `last-modified` 的协商缓存
<!-- ```js
// 1.首先需要在服务器端读出文件修改时间
// 2.将读出来的修改时间赋给响应头的 last-modified 字段
// 3.最后设置 Cache-control:no-cache
``` -->

- 2.2.基于 `ETag` 的协商缓存

`koa服务` 设置get请求协商缓存
```js
const koa = require('koa')
const router = require('koa-router')()
const static = require('koa-static')
const conditional = require('koa-conditional-get');
const etag = require('koa-etag');

const app = new koa()
app.use(static(__dirname + '/public'))
app.use(require('koa2-cors')()) // 允许跨域访问

// 使用中间件设置协商缓存
app.use(conditional());
app.use(etag());

router.get('/test', (ctx) => {
ctx.body = '测试'
})

app.listen(3000, () => {
console.log('koa服务已启动port:http://localhost:3000/')
})
```

`express服务` 设置get请求协商缓存
```js
const express = require('express')
const app = express()
app.use(express.static('public'))


//设置允许跨域访问该服务.
app.all('*', function (req, res, next) {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Credentials', 'true') // 允许跨域携带凭证
res.header('Access-Control-Allow-Headers', 'Content-Type')
res.header('Access-Control-Allow-Methods', '*')
res.header('Content-Type', 'application/json;charset=utf-8') // 中文乱码解决
next()
})

const etag = require('etag')

app.get('/test', (req, res) => {
const hash = etag(content)
// 协商缓存
res.set({
ETag: hash,
'Cache-Control': 'no-cache',
})

if (req.headers['if-none-match'] === hash) {
res.status(304).end()
} else {
res.send('测试')
}
})

app.listen(3000, () => {
console.log('express服务已启动port:http://localhost:3000/')
})
```
node 内置的 `http服务` 设置get请求协商缓存
```js
const fs = require('fs')
const path = require('path')
const http = require('http')
const etag = require('etag')

const server = http.createServer((req, res) => {
const { url, method } = req
// 设置跨域响应头
res.setHeader('Access-Control-Allow-Origin', '*')
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS')
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type')

if (url === '/' && method == 'GET') {
// 静态资源
fs.readFile(path.join(__dirname, 'public/index.html'), (err, data) => {
if (err) throw err
res.StatusCode = 200
res.setHeader('Content-Type', 'text/html')
res.end(data)
})
} else if (url === '/test' && method === 'GET') {
// 协商缓存
const etagValue = etag('test123')
res.setHeader('ETag', etagValue)

- 2.2.基础 `ETag` 的协商缓存
// 检查是否命中缓存
if (req.headers['if-none-match'] === etagValue) {
res.writeHead(304, 'Not Modified')
res.end()
} else {
// 发送响应数据
res.writeHead(200, { 'Content-Type': 'text/plain' })
res.end(
JSON.stringify({
name: '测试',
})
)
}
}
})

server.listen(3000, () => {
console.log('http服务已启动port:http://localhost:3000/')
})
```

### `3.如何判断get请求是否做了协商缓存`
在没有勾选停用缓存的情况下、如果GET请求的code码为304、则一定做了协商缓存、其次如果code码不是304、在多次请求同一个接口时、首次接口的大小和后面请求的大小不一致、也是做了协商缓存、如下图所示:红框和黄框的文件大小区别
<p align="left">
<img src="/AA_mdPics/hello.min.png" />
</p>

### `3.总结`
### `4.总结`
- 关于强缓存、`cache-control``Expires` 的完全替代方案、在可以使用 `cache-control` 的情况下不要使用 `expires`
- 关于协商缓存、`etag` 并不是 `last-modified` 的完全替代方案、而是补充方案、具体用哪一个、取决于业务场景
- <u>所有返回304状态码的资源都是</u>` 协商缓存`、<u>所有标注(从内存中读取/从磁盘中读取)的资源都是</u>` 强缓存`
- 统一有后端设置 或 Nginx做配置
- 统一有后端设置 或 Nginx做配置
- 强缓存的应用场景适合不经常变动的资源请求如:图片、css、js文件、而对于经常更新的资源请求、可以设置304协商缓存做优化

0 comments on commit 4230648

Please sign in to comment.