当前位置: 首页 > news >正文

初窥 HTTP 缓存

引言

对于前端来说, 你肯定听说过 HTTP 缓存。 当然不管你知不知道它, 对于提高网站性能和用户体验, 它都扮演着重要的角色! 它通过在客户端和服务器之间存储和重用先前获取的资源副本, 来减少网络流量和降低资源加载时间, 从而提升用户体验! 以下是 HTTP 缓存的重要性:

  1. 减少加载时间: 通过使用缓存, 浏览器可以重用已下载的资源, 而不必每次都从服务器重新请求。这减少了页面加载时间, 提高了用户体验, 尤其是在较慢的网络连接下
  2. 降低服务器负载: HTTP 缓存可以减少服务器的负载, 因为不再需要为相同的资源处理大量重复请求。这有助于减少服务器资源的使用, 降低运营成本
  3. 减少网络流量: HTTP 缓存可以减少不必要的网络流量, 因为浏览器可以从本地缓存中加载资源, 而不必每次都从服务器下载。这有助于减少带宽成本, 尤其是对于大型网站来说
  4. 提高用户体验: 快速加载的网页提供更好的用户体验, 吸引更多的访问者, 并增加用户留存率。缓存使用户能够更快地访问网站内容, 从而提高了他们的满意度

实际开发中我们有时为了避免因为缓存导致资源没有更新, 常常会简单而粗暴的为资源文件路径添加一个时间戳! 该方式虽然有效, 也能解决实际问题, 但过于粗暴了, 我们完全可以采用更加优雅的方式。本文将对 HTTP 缓存进行一个详细的讲解, 来帮助大家对 HTTP 缓存有一个较深的理解, 帮忙大家在实际项目中设计出更为合理、高效的缓存方案!!

补充(偶然看到一句话, 送给大家): 所有的技术都是为了解决问题而存在的, 在不了解问题情况下强行记忆, 效果肯定是打折扣的!!

本文使用到的 DEMO 地址点 这里

一、强缓存

首先在上文我们已经强调了 HTTP 缓存的一个重要性, 那么要想设计一个缓存方案, 最简单的办法就是根据资源加载的时间:

  • 首次加载资源时将资源缓存起来
  • 然后在指定时间内如果加载同一份资源, 则客户端(浏览器)直接使用缓存数据, 而不向服务器发起任何请求
  • 当然如果超时则会发起新的请求获取资源, 然后再次缓存起来

image

而这种不发起任何请求(没经过服务端), 直接由客户端(浏览器)自行决定是否使用缓存的方案, 则被称为 强缓存!!

1.1 Expires

Expires 响应头, 表示当前获取到的资源的过期时间, 该时间是一个 GMT 时间, 即格林尼治时间!!

image

当客户端(浏览器)再次获取资源前:

  • 如果 存在未到期 的缓存资源, 则直接获取缓存的资源, 不发起任何请求!!
  • 如果 不存在缓存资源 或者 缓存的资源已过期, 则向服务器发起请求获取资源, 并再次缓存资源

image

特别注意的是, ExpiresHTTP/1.0 的产物了, 现在大部分浏览器均默认使用 HTTP/1.1 所以它的作用基本可以忽略!!

image

但这里其实有一个问题, Expires 时间是由服务端生成的, 这时如果客户端时间跟服务器时间不一致, 就会导致缓存命中的误差!!

所以后面就有了 Cache-Control

1.2 Cache-Control

Cache-Control 响应头, HTTP/1.1 出现的一个响应头, 它弥补了 Expires 的缺陷:

  • Expires 是直接由服务端给定一个资源过期时间
  • Cache-Control 则不同, 服务端只会告诉客户端该资源的有效期! 就比如, 它有一个 max-age 字段, 当它被设置为 10, 则表示当前资源有效期为 10 秒, 10 秒过后资源缓存将失效

image

Cache-Control 相对来说使用起来也更为复杂, 可设置的属性也比较多。当然复杂也说明它可适用于更广泛的复杂场景, 下面我们来看下 Cache-Control 响应头的语法规则:

  • 不区分大小写, 但建议使用小写
  • 多个指令以逗号分隔
  • 具有可选参数, 可以用令牌或者带引号的字符串语法

Cache-Control 可选属性有: 注意 no-cacheno-store 的区别, no-store 才是禁用 强缓存

类型属性描述
可缓存性public表明响应可以被任何对象(发送请求的客户端、代理服务器等等)缓存
可缓存性private私有缓存, 响应只能被单个客户端缓存
可缓存性no-cache无论本地缓存是否过期, 都需要请求源服务器进行验证(协商缓存验证)
可缓存性no-store不使用任何缓存
到期时间max-age=<seconds>设置缓存有效期的最大周期, 超过这个时间缓存被认为过期(单位秒)
到期时间s-maxage=<seconds>max-age, 但是仅适用于共享缓存(代理服务器), 生效时会覆盖 max-age 或者 Expires
到期时间max-stale[=<seconds>]表明客户端愿意接收一个已经过期的资源, 可以设置一个可选的秒数, 表示缓存允许过期的最大值
到期时间min-fresh=<seconds>希望在一个指定的秒数内保持资源的最新, 也就是说在设定的时间内获取资源不管缓存有没效, 都需要发起缓存进行验证(协商缓存验证)
到期时间stale-while-revalidate=<seconds>实验版, 有点类似 max-stale, 客户端愿意接收一个已经过期的资源, 同时客户端会在后台异步获取新的资源; 可以设置一个秒数, 表示允许接受陈旧缓存的最大值
到期时间stale-if-error=<seconds>实验版, 如果新的检查失败, 则客户端愿意接受陈旧的响应, 设置的秒数值表示客户端在初始到期后愿意接受陈旧响应的时间
重新验证或重新加载must-revalidate如果本地副本未过期, 可以使用本地副本; 否则, 需要请求源服务器进行验证
重新验证或重新加载proxy-revalidatemust-revalidate 作用相同, 但它仅适用于共享缓存(例如代理服务器), 对于私有缓存(本地缓存)该值会被忽略
重新验证或重新加载immutable实验版, 表示缓存一直有效, 再也不会发起请求了
其他no-transform不允许对资源进行转换或转变, Content-EncodingContent-RangeContent-TypeHTTP 头允许被代理服务修改
其他only-if-cached客户端只接受已缓存的响应, 不会进行任何请求, 如果缓存不命中则返回错误

下面我们来测试下, 如下代码是使用 Koa 搭建的一个简单服务:

  • 代码中实现了一个 GET 接口 /api/cache-control
  • 在接口 /api/cache-control 响应体中设置了 Cache-Control 响应头, 值为 public,max-age=120
  • 那么当客户端访问 /api/cache-control 理论上, 请求的响应内容会被任何端缓存起来, 缓存有效期 120s
const Koa = require('koa');
const moment = require('moment');
const cors = require('@koa/cors')
const Router = require('@koa/router');const app = new Koa();
const router = new Router();// 跨域设置
app.use(cors({maxAge: 5,origin: "*",credentials: true,allowMethods: ['GET', 'POST'],allowHeaders: ['Content-Type'],exposeHeaders: ['Content-Type'],
}));// 2. Cache-Control
router.get('/api/cache-control', async (ctx) => {ctx.status = 200;ctx.body = 111111111;ctx.set('Cache-Control', `public,max-age=120`);
});app.use(router.routes()).use(router.allowedMethods());
app.listen(3000);

1.3 Pragma

Pragma 是一个在 HTTP/1.0 中规定的响应头, 它只有一个属性值, 就是 no-cache, 其效果和 Cache-Control 中的 no-cache 是一致的, 表明不使用强缓存, 需要客户端(浏览器)与服务器验证缓存是否有效, Pragma 在本节的 3 个头部属性中的优先级是最高的

image

也许你会奇怪为啥有了 Cache-Control 还要整个 Pragma, 这里你需要注意的是 Cache-Control 其实是后面 HTTP/1.1 才出来的, 在 Cache-Control 之前 Pragma 是作为 Expires 的一个补充!!

当然 Pragma 目前主要就是用于向后兼容那些只支持 HTTP/1.0 协议的客户端!!

二、协商缓存

上文几个响应头, 客户端、服务端是通过约定缓存有效时间来决定, 是否 直接 使用本地缓存!! 但是这个方案其实存在很明显的问题:

  • 假设我们约定每次资源缓存的有效时间为 2 分钟
  • 但是呢? 2 分钟内, 如果服务端资源更新了, 按强缓存来, 这时客户端拿到的资源都是缓存内容, 就无法保证资源的最新
  • 同样, 如果服务端资源一直不更新, 那么 2 分钟后, 客户端如果发起请求这时将会重新获取资源, 这就不可避免的造成资源的浪费

那么要想解决上面这个问题, 就可以使用 协商缓存, 其实所谓 协商缓存 就是客户端(浏览器)在请求资源时先向服务端进行 协商: 客户端(浏览器)向服务端询问本地缓存的资源是否是最新的

  • 如果本地缓存的资源 未过期, 那么服务端就会将请求状态码设置为 304(Not Modified), 这时请求不会返回任何 body, 客户端(浏览器)将直接使用本地缓存
  • 如果本地缓存已过期, 那么服务端正常处理请求, 状态码设置为 200, 这时的 body 将是完整的资源内容

image

那么服务端如何判断客户端本地的缓存不是最新的呢? 它们之间又是怎么协调的呢?

2.1 Last-Modified / If-Modified-Since

第一个方案其实就是根据 资源最后修改时间 来进行判断:

  • 当客户端首次请求资源时, 服务端会把资源的最后修改时间放到 Last-Modified 响应头中(浏览器自动将 Last-Modified 也缓存起来)
  • 当客户端再次请求资源时, 浏览器会通过 If-Modified-Since 请求头, 将本地缓存资源对应最后修改时间带上(这个是浏览器自己的行为, 不需要我们认为去处理)
  • 服务端就可以根据 If-Modified-Since 来判断客户端(浏览器)的资源是否是最新的
  • 如果是客户缓存的资源是最新的, 则 body 直接返回空, 同时将状态码改为 304(Not Modified)
  • 否则按首次请求资源处理, 状态码为 200, body 为请求的资源内容

image

下面使用 Koa 搭建的一个简单服务:

  • 在接口中我们将客户端请求头中的 if-modified-since 和当前的 Last-Modified 进行比较
  • 如果相同, 则表示客户端的资源是最新的, 则不返回任何内容(body 为空), 让客户端直接使用缓存(状态码设置为 304)
  • 如果不相同, 则表示客户端的资源不是最新的, 则正常返回内容(状态码为 200, body 为当前资源内容), 当然这时还需要带上 Last-Modified
const Koa = require('koa');
const moment = require('moment');
const cors = require('@koa/cors')
const Router = require('@koa/router');const app = new Koa();
const router = new Router();// 跨域设置
app.use(cors({maxAge: 5,origin: "*",credentials: true,allowMethods: ['GET', 'POST'],allowHeaders: ['Content-Type'],exposeHeaders: ['Content-Type'],
}));// 4. Last-Modified / If-Modified-Since
const lastModified = 'Thu, 09 Nov 2023 06:37:41 GMT'
router.get('/api/last-modified', async (ctx) => {// 客户端本地缓存最新更改时间和当前的一致 => 让客户端直接使用缓存吧if (ctx.request.header['if-modified-since'] === lastModified) {ctx.status = 304;ctx.body = '2222'} else {// 返回最新内容ctx.status = 200;ctx.body = '111111111'}ctx.set('Last-Modified', lastModified);ctx.set('Cache-Control', 'no-cache');
});app.use(router.routes()).use(router.allowedMethods());app.listen(3000);

image

这里有个奇怪的现象, 第二次请求时, 服务器实际上设置的状态码为 304, body 内容为 2222, 但是在 chrome 中查看的话会发现展示出来的状态码为 200, body 为缓存的数据!!

image
image

猜测: chrome 针对本地存在缓存的 304 接口做了处理, 这里有一篇文章可供参考 《为什么Chrome开发工具显示200状态代码而不是 304? 》, 具体原因就不细究了…

2.2 ETag / If-None-Match

「根据最后修改时间, 来判定客户端缓存是否是最新的资源」这个依据在大部分情况应该是有效的!! 但是也避免不了一种情况就是, 资源更新时间变了, 但是呢内容和之前却是一样的(比如项目重新打包、资源修改一版又撤销回去…)

这种情况下, 我们就可以使用 ETag 来判断资源是否有效!!! ETag 作为资源内容的唯一标记被使用, 它可以是资源内容对应的一个唯一 ID, 也可以是根据资源文件内容生成的一个 MD5, 总之它代表的当前资源的一个唯一值!!

ETag 在服务端和客户端之前的工作流程和 Last-Modified 基本一致:

  • 当客户端首次请求资源时, 服务端会把当前资源对应唯一标记放到 ETag 响应头中(浏览器会将 ETag 也缓存起来)
  • 当客户端再次请求资源时, 浏览器会通过 If-None-Match 请求头, 将本地缓存资源对应的 ETag 带上(浏览器自己的行为)
  • 服务端就可以根据 If-None-Match 以及当前资源的 ETag 来判断客户端(浏览器)的资源是否是最新的
  • 如果客户缓存的资源是最新的, 则 body 直接返回空, 同时将状态码改为 304(Not Modified)
  • 否则按首次请求资源处理, 同时带上 ETag

image

下面使用 Koa 搭建的一个简单服务:

  • 在接口中我们将客户端请求头中的 if-none-match 和当前的 ETag 进行比较
  • 如果相同, 则表示客户端的资源是最新的, 则不返回任何内容(body 为空), 让客户端直接使用缓存(状态码设置为 304)
  • 如果不相同, 则表示客户端的资源不是最新的, 则正常返回内容(状态码为 200, body 为当前资源内容), 当然这时还需要带上 ETag
const Koa = require('koa');
const moment = require('moment');
const cors = require('@koa/cors')
const Router = require('@koa/router');const app = new Koa();
const router = new Router();// 跨域设置
app.use(cors({maxAge: 5,origin: "*",credentials: true,allowMethods: ['GET', 'POST'],allowHeaders: ['Content-Type'],exposeHeaders: ['Content-Type'],
}));// 5. ETag / If-None-Match
const ETag = '33a64df551425fcc55e4d42a148795d9f25f89d4'
router.get('/api/etag', async (ctx) => {// 客户端本地缓存最新 ETag 和当前的一致 => 让客户端直接使用缓存吧if (ctx.request.header['if-none-match'] === ETag) {ctx.status = 304;ctx.body = '2222'} else {// 返回最新内容ctx.status = 200;ctx.body = '111111111'}ctx.set('ETag', ETag);ctx.set('Cache-Control', 'no-cache');
});app.use(router.routes()).use(router.allowedMethods());app.listen(3000);

image

同上文, 如果本地缓存有效, 并且服务端状态码为 304, chrome 展示状态码也只会是 200, 内容为缓存的内容

2.3 补充: If-Unmodified-Since / If-Match

上文提到的几个消息头, 都只是在获取资源(get 请求)情况下生效!! If-Unmodified-SinceIf-Match 则是在修改内容的情况下生效, 比如 postputremove 等请求:

  • 当客户端(浏览器)发起请求试图修改资源时, 可以携带上 If-Unmodified-Since(本地资源对应 Last-Modified)If-Match(本地资源 ETag)
  • 服务端通过请求头中的 If-Unmodified-SinceIf-Match 来判断服务端资源是否已经被修改过(当前本地资源是否是最新的)
  • 如果服务端的资源已经被修改过, 那么服务端直接返回 412 (Precondition Failed) 错误, 不处理本次请求
  • 相反, 则返回 200! 正常处理请求

image

三、优先级

  1. 首先强缓存优先级大于协商缓存, 只有在强缓存失效情况下, 然后才会和服务端建立连接进行协商
  2. 强缓存中: Pragma > Cache-Control > Expires
  3. 协商缓存中: ETag > Last-Modified, 因为 ETag 更为精准

四、参考

  • 30分钟搞懂 HTTP 缓存
  • 前端应该知道 HTTP 缓存机制
  • 从未如此简单 5 分钟搞懂 HTTP 缓存机制
  • 彻底搞懂 HTTP 缓存策略,切记死背概念!
  • HTTP 缓存看这一篇就够了
  • 图解 HTTP 缓存
  • 轻松理解 HTTP 缓存策略
  • 面试官: 你懂 HTTP 缓存,那说下浏览器强制刷新是怎么实现的?

image

相关文章:

初窥 HTTP 缓存

引言 对于前端来说, 你肯定听说过 HTTP 缓存。 当然不管你知不知道它, 对于提高网站性能和用户体验, 它都扮演着重要的角色! 它通过在客户端和服务器之间存储和重用先前获取的资源副本, 来减少网络流量和降低资源加载时间, 从而提升用户体验! 以下是 HTTP 缓存的重要性: 减少…...

【LeetCode】3. 哈希表: 字母异位词分组;有效的数独

题目 字母异位词分组 给你一个字符串数组&#xff0c;请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs [“eat”, “tea”, “tan”, “ate”, “nat”, “bat”] 输出: [[“…...

设计模式之抽象工厂 C# 范例

在设计模式中&#xff0c;抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09; 是一种创建型模式&#xff0c;它提供一个接口&#xff0c;用于创建一组相关或相互依赖的对象&#xff0c;而无需指定具体类。这种模式的关键在于通过抽象工厂来封装产品的创建&#xff…...

基于Python的猎聘网招聘数据采集与可视化分析

1.1项目简介 在现代社会&#xff0c;招聘市场的竞争日趋激烈&#xff0c;企业和求职者都希望能够更有效地找到合适的机会与人才。猎聘网作为国内领先的人力资源服务平台&#xff0c;汇聚了大量的招聘信息和求职者数据&#xff0c;为研究招聘市场趋势提供了丰富的素材。基于Pyt…...

oracle数据库的启动与关闭

一.oracle数据库的启动过程 启动实例&#xff08;Start the Instance&#xff09; 启动实例&#xff1a;一个Oracle数据库实例由内存结构和后台进程组成&#xff0c;启动实例时会加载这些内存结构和启动进程。实例是数据库的一个运行时环境&#xff0c;它包含了数据库的控制文…...

openGauss开源数据库实战十六

文章目录 任务十六 openGauss逻辑结构:触发器管理任务目标实施步骤一、测试openGauss的触发器1.创建测试表2.创建触发器对应的函数3.创建触发器4.测试触发器 二、触发器的类型1.行级触发器2.语句级触发器3.AFTER触发器和 BEFORE触发器 任务十六 openGauss逻辑结构:触发器管理 …...

智能教育的关键之一是构建智能学习系统

教育部办公厅12月27日发布《关于加强中小学人工智能教育的通知》&#xff0c;提出人工智能教育六大主要任务和举措&#xff0c;包括构建系统化课程体系、实施常态化教学与评价、开发普适化教学资源、建设泛在化教学环境、推动规模化教师供给和组织多样化交流活动。《通知》提出…...

【Linux 篇】Docker 容器星河与镜像灯塔:Linux 系统下解锁应用部署奇幻征程

文章目录 【Linux 篇】Docker 容器星河与镜像灯塔&#xff1a;Linux 系统下解锁应用部署奇幻征程前言一 、docker上部署mysql1. 拉取mysql镜像2. 创建容器3. 远程登录mysql 二 、docker上部署nginx1. 拉取nginx镜像2. 在dockerTar目录下 上传nginx.tar rz命令3. 创建nginx容器4…...

十四(AJAX)、AJAX、axios、常用请求方法(GET POST...)、HTTP协议、接口文档、form-serialize

1. AJAX介绍及axios基本使用 <!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8" /><meta http-equiv"X-UA-Compatible" content"IEedge" /><meta name"viewport" content&q…...

雪花算法生成ID

下面将简单介绍雪花算法的简单应用和在web应用中的使用。 雪花算法的组成&#xff1a;雪花算法是由64位组成&#xff1a;符号位(1)、时间戳(41)、机器码(5[数据中心]5[机器ID])、计数器(12) 对于雪花算法的源码可以在这里看&#xff1a;bwmarrin/snowflake: A simple to use …...

Java - JSR223规范解读_在JVM上实现多语言支持

文章目录 1. 概述2. 核心目标3. 支持的脚本语言4. 主要接口5. 脚本引擎的使用执行JavaScript脚本执行groovy脚本1. Groovy简介2. Groovy脚本示例3. 如何在Java中集成 Groovy4. 集成注意事项 6. 与Java集成7. 常见应用场景8. 优缺点9. 总结 1. 概述 JSR223&#xff08;Java Spe…...

vue3 基本使用

Vue 3 提供了多种方式来构建用户界面&#xff0c;包括选项式 API 和 Composition API。下面我将详细介绍 Vue 3 的基本使用和语法&#xff0c;主要集中在选项式 API 上&#xff0c;因为这对于初学者来说更容易上手。 1. 创建 Vue 项目 如果你还没有一个 Vue 项目&#xff0c;…...

Redis自学之路—高级特性(实现消息队列)(七)

目录 简介 Redis的Key和Value的数据结构组织 全局哈希表 渐进式rehash 发布和订阅 操作命令 publish 发布消息 subscribe 订阅消息 psubscribe订阅频道 unsubscribe 取消订阅一个或多个频道 punsubscribe 取消订阅一个或多个模式 查询订阅情况-查看活跃的频道 查询…...

ROS基本框架2——在ROS开发中创建并使用自定义消息(C++版本)

ROS基本框架2——在ROS开发中创建并使用自定义消息(C++版本) code review! 参考笔记 1.ROS基本框架1——编写简单的发布者和订阅者(C++和Python版本) 2.ROS基本框架2——在ROS开发中创建并使用自定义消息(C++版本) 文章目录 ROS基本框架2——在ROS开发中创建并使用自定义…...

计算机的错误计算(一百七十二)

摘要 探讨 MATLAB 对于算式 的计算误差。 例1. 在 MATLAB 中计算 的值。 直接贴图吧&#xff1a; 这样&#xff0c;MATLAB 的输出中只有3位正确数字&#xff0c;有效数字的错误率为 (16-3)/16 81.25% . 因为16位的正确输出为 0.2971242332737277e-18&#xff08;ISReals…...

贵州大学oj平台高级语言第九次作业(四)

题目&#xff1a;链表的基础操作 题目描述 链表是软件中一种最基本的数据结构&#xff0c;它是用链式存储结构实现数据存储的线性表。它较顺序表(如数组)而言在插入和删除数据时不必移动其后的大批量元素。现在给你一些整数&#xff0c;然后会频繁地插入和删除其中的某些元素&a…...

手机卡限速丨中国移动5G变3G,网速500kb

以下猜测错误&#xff0c;又有新的猜测&#xff1a;河南移动的卡出省限速。可能是因为流量结算。 “2024年7月1日起&#xff0c;中国移动集团内部将开启跨省流量结算” 在深圳四五年了&#xff0c;之前没有过&#xff0c;就从上个月开始。11月底解除限速&#xff0c;12月刚开…...

种花问题算法

假设有一个很长的花坛&#xff0c;一部分地块种植了花&#xff0c;另一部分却没有。可是&#xff0c;花不能种植在相邻的地块上&#xff0c;它们会争夺水源&#xff0c;两者都会死去。 给你一个整数数组 flowerbed 表示花坛&#xff0c;由若干 0 和 1 组成&#xff0c;其中 0 …...

Node.js-Mongodb数据库

MongoDB MongoDB是什么&#xff1f; MongoDB是一个基于分布式文件存储的数据库 数据库是什么&#xff1f; 数据库&#xff08;DataBase&#xff09;是按照数据结构来组织、存储和管理数据的应用程序&#xff08;软件&#xff09; 数据库作用&#xff1f; 对数据进行增、删…...

Nginx

目录 基本介绍 Nginx核心功能 Nginx下载&安装&启动 配置防火墙 Nginx常用命令 Nginx配置文件 全局块 events块 http块 http全局块 server 块 检查配置信息 快速入门 安装JDK 安装Tomcat 反向代理分析 Location语法规则 反向代理配置-Location实例 …...

CTF-PWN: 全保护下格式化字符串利用 [第一届“吾杯”网络安全技能大赛 如果能重来] 赛后学习(没思路了)

通过网盘分享的文件&#xff1a;如果能重来.zip 链接: https://pan.baidu.com/s/1XKIJx32nWVcSpKiWFQGpYA?pwd1111 提取码: 1111 --来自百度网盘超级会员v2的分享漏洞分析 格式化字符串漏洞,在printf(format); __int64 sub_13D7() {char format[56]; // [rsp10h] [rbp-40h]…...

HTML5系列(7)-- Web Storage 实战指南

前端技术探索系列&#xff1a;HTML5 Web Storage 实战指南 &#x1f5c4;️ 致读者&#xff1a;本地存储的新纪元 &#x1f44b; 前端开发者们&#xff0c; 今天我们将深入探讨 HTML5 中的 Web Storage 技术&#xff0c;这是一个强大的本地存储解决方案&#xff0c;让我们能…...

RocketMQ: 保证消息的可靠性投递

概述 在分布式系统中&#xff0c;消息队列作为异步通信的重要组件&#xff0c;其可靠性和稳定性至关重要RocketMQ 是阿里巴巴开源的一款高性能、高可靠性的分布式消息中间件&#xff0c;广泛应用于各种场景&#xff0c;如交易订单处理、日志收集、流计算等 RocketMQ 的可靠性…...

消息传递神经网络(Message Passing Neural Networks, MPNN)

消息传递神经网络&#xff08;Message Passing Neural Networks, MPNN&#xff09; 一、引言二、消息传递框架概述1.消息传递阶段&#xff08;1&#xff09;消息生成与传播-message&#xff08;2&#xff09;消息聚合-aggregate&#xff08;3&#xff09;消息更新-update&#…...

Python干货总结篇:列表、字典、集合、元组的区别与用途

前言&#xff1a; 更详细知识点&#xff0c;搞懂列表、字典、集合、元组到底是什么&#xff0c;可关注主页文章&#xff1a;Python知识点精汇&#xff01; 目录 一、特点与用途 1.列表&#xff1a;a[ ] 2.集合&#xff1a;a{ } 3.字典&#xff1a;a{key:value} 4.元组&am…...

vue.js学习(day 18)

实例&#xff1a;面经基础版...

【Gitlab】CICD使用minio作为分布式缓存

1、安装minio 下载适合自己系统版本的安装文件https://dl.min.io/server/minio/release/windows-amd64/ yum install xxx.rpm 2、配置/etc/profile export MINIO_ACCESS_KEYroot [ui登录账号] export MINIO_SECRET_KEYminioDev001 [ui登录密码] export MINIO_OPTS"…...

医院管理系统

私信我获取源码和万字论文&#xff0c;制作不易&#xff0c;感谢点赞支持。 医院管理系统 摘要 随着信息互联网信息的飞速发展&#xff0c;医院也在创建着属于自己的管理系统。本文介绍了医院管理系统的开发全过程。通过分析企业对于医院管理系统的需求&#xff0c;创建了一个计…...

编译器优化技术

方法内联 逃逸分析 公共子表达式消除 数据边界检查消除...

高斯消元——acwing

题目一&#xff1a;高斯消元解线性方程组 883. 高斯消元解线性方程组 - AcWing题库 分析 代码 #include<bits/stdc.h> using namespace std;const int N 110; const double eps 1e-6; // 注意了double, 和1e-6 ,,这样才是double的0 int n;double a[N][N];int guass…...

华为关键词覆盖应用市场ASO优化覆盖技巧

在我国的消费者群体当中&#xff0c;华为的品牌形象较高&#xff0c;且产品质量过硬&#xff0c;因此用户基数也大。与此同时&#xff0c;随着影响力的增大&#xff0c;华为不断向外扩张&#xff0c;也逐渐成为了海外市场的香饽饽。作为开发者和运营者&#xff0c;我们要认识到…...

[代码随想录06]哈希表的使用,有效字母异位词,两数组交集,快乐数,两数之和

前言 哈希表是什么&#xff1f;一句话带你理解&#xff0c;简单来说我们对于杂乱的数据&#xff0c;怎么快速找到数据&#xff0c;如何做呢&#xff1f;一般的做法就是遍历复杂度为o(N)去找寻一个数据&#xff0c;但是吧&#xff0c;我们这样思考的话&#xff0c;还是花了大量时…...

linux网络抓包工具

linux网络抓包工具 一、tcpdump1.1 基本用法1.2 龙芯平台实例操作 二、wireshark2.1 主要功能2.2 龙芯平台实例操作 一、tcpdump tcpdump 指令可列出经过指定网络界面的数据包文件头&#xff0c;可以将网络中传送的数据包的 “头” 完全截获下来提供分析。它支持针对网络层、协…...

运维工程师.云计算工程师面试题.考试题

《(全国)运维自动化阶段第1套卷》 卷面总分 题号 单选题 90 题分 得分 一、单选题(每题2分,共计70分;得分____) 1. 下面哪个选项可以做变量名称?( ) A、if B、123abc C、for D、User_Name 2. 哪种数据类型可以做增,删,改相关操作?( ) A、字符串 B、列表 C、元…...

递归1——递归入门

目录 1.递归 2.递归的基本题目 2.1.题目一——P5739 【深基7.例7】计算阶乘 - 洛谷 | 计算机科学教育新生态 2.2.题目二——B2064 斐波那契数列 - 洛谷 | 计算机科学教育新生态 2.3.题目三——B2142 求 123...N 的值 - 洛谷 | 计算机科学教育新生态 2.4.题目四——B2144…...

XuperChain核心流程

04-XuperChain核心流程 0 XuperChain架构图 核心框架 Xuper Chain主要由 Xuper Core 这个核心引擎来构建。Xuper Core 分为三个部分&#xff1a; 基础组件&#xff1a;日志、存储、监控等关键组件&#xff0c;以及密码学库等基本组件。 核心组件&#xff1a;包括共识、合约、账…...

2024.12.2工作复盘

1.今天学了什么&#xff1f; 简单的写了一篇博客&#xff0c;是关于参数校验的问题&#xff0c;参数校验&#xff0c;一个是前后端校验到底一不一致&#xff0c;一个是绕过前端校验&#xff0c;看后台的逻辑到底能不能校验住。 2.今天解决了什么问题&#xff1f; 3.今天完成…...

关于Vscode配置Unity环境时的一些报错问题(持续更新)

第一种报错&#xff1a; 下载net请求超时&#xff08;一般都会超时很正常的&#xff09; 实际时并不需要解决&#xff0c;它对你的项目毫无影响 第二种报错&#xff1a; .net版本不匹配 解决&#xff1a;&#xff08;由于造成问题不一样&#xff0c;所以建议都尝试一次&…...

微信小程序——文档下载功能分享(含代码)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

长短期记忆网络 (LSTM) 简介

文章目录 一、说明二、传统 RNN 的问题三、为什么梯度消失&#xff1f;四、长短期记忆网络简介五、忘记门六、Update Gate (Input Gate)七、Output Gate八、数学上的内存九、从 LSTM 到 Transformer十、总结 一、说明 机器学习取得进步的领域之一是自然语言处理。对于用于机器…...

【电子通识】USB Type-C线缆为什么有的用到E-Marker芯片

USB Type-C接口具备数据传输、充电(基于USB PD协议)和音频视频传输能力。但是,上述功能都有强弱之别,并因此衍生出了无数种规格的USB Type-C线缆。 如下所示直接搜索就可以看到,虽然都是Type-C接口,但存在很多不同种类的线缆规格。 以数据传输为例,USB Type-C可选USB2.0…...

【故障处理系列--移动云云盘根目录在线扩容】

移动云云盘根目录扩容 **目的&#xff1a;**测试harbor仓库服务器的根目录能否在线扩容 1、移动云控制台系统盘扩容 这里以我自己的虚拟机演示 2、查看分区的文件类型 3、安装growpart工具 rootgitlab-cli:~# apt install cloud-guest-utils -y rootgitlab-cli:~# apt ins…...

混沌工程/混沌测试/云原生测试/云平台测试

背景 私有云/公有云/混合云等具有复杂&#xff0c;分布式&#xff0c;环境多样性等特点&#xff0c;许多特殊场景引发的线上问题很难被有效发现。所以需要引入混沌工程&#xff0c;建立对系统抵御生产环境中失控条件的能力以及信心&#xff0c;提高系统面对未知风险得能力。 …...

CQ 社区版 2024.11 | 新增“审批人组”概念、可通过SQL模式自定义审计图表……

CloudQuery 社区 11 月新版本来啦&#xff01;本月版本依旧是 CUG&#xff08;CloudQuery 用户组&#xff09;尝鲜版的更新。 针对审计模块增加了 SQL 模式自定义审计图表&#xff1b;在流程模块引入了“审批人组”概念。此外&#xff0c;在 SQL 编辑器、连接管理等模块都涉及…...

【maven-4】IDEA 配置本地 Maven 及如何使用 Maven 创建 Java 工程

IntelliJ IDEA&#xff08;以下简称 IDEA&#xff09;是一款功能强大的集成开发环境&#xff0c;广泛应用于 Java 开发。下面将详细介绍如何在 IDEA 中配置本地 Maven&#xff0c;并创建一个 Maven Java 工程&#xff0c;快速上手并高效使用 Maven 进行 Java 开发。 1. Maven …...

c语言结构体

c语言结构体 1. 结构体的定义 在C语言中&#xff0c;结构体是一种用户自定义的数据类型&#xff0c;它允许你将不同类型的数据组合成一个单一的实体。结构体的定义以struct关键字开头&#xff0c;后面跟着结构体标签&#xff08;可以省略&#xff0c;但为了方便后续引用&#…...

洛谷二分题

P1024 [NOIP2001 提高组] 一元三次方程求解 题目描述 有形如&#xff1a;&#x1d44e;&#x1d465;3&#x1d44f;&#x1d465;2&#x1d450;&#x1d465;&#x1d451;0ax3bx2cxd0 这样的一个一元三次方程。给出该方程中各项的系数&#xff08;&#x1d44e;,&#x1d44…...

vue3的项目目录和关键文件

注意换插件 vue2的是 Vetur &#xff1b;vue3的是volar 这里注意volar插件已更名为Vue - Official vite.config.js 放跟vite配置相关的内容 区别于vue2&#xff1b;vue2是vue.config.js&#xff1b;vue2是基于webpack的&#xff0c;vue3是基于vite的 main.js import { creat…...

rabbitmq原理及命令

目录 一、RabbitMQ原理1、交换机&#xff08;Exchange&#xff09;fanoutdirecttopicheaders&#xff08;很少用到&#xff09; 2、队列Queue3、Virtual Hosts4、基础对象 二、RabbitMQ的一些基本操作:1、用户管理2、用户角色3、vhost4、开启web管理接口5、批量删除队列 一、Ra…...

洛谷 P1308 [NOIP2011 普及组] 统计单词数 C语言

题目&#xff1a; https://www.luogu.com.cn/problem/P1308 复制Markdown 展开 题目描述 一般的文本编辑器都有查找单词的功能&#xff0c;该功能可以快速定位特定单词在文章中的位置&#xff0c;有的还能统计出特定单词在文章中出现的次数。 现在&#xff0c;请你编程实现…...