初窥 HTTP 缓存
引言
对于前端来说, 你肯定听说过 HTTP 缓存。 当然不管你知不知道它, 对于提高网站性能和用户体验, 它都扮演着重要的角色! 它通过在客户端和服务器之间存储和重用先前获取的资源副本, 来减少网络流量和降低资源加载时间, 从而提升用户体验! 以下是 HTTP 缓存的重要性:
- 减少加载时间: 通过使用缓存, 浏览器可以重用已下载的资源, 而不必每次都从服务器重新请求。这减少了页面加载时间, 提高了用户体验, 尤其是在较慢的网络连接下
- 降低服务器负载:
HTTP缓存可以减少服务器的负载, 因为不再需要为相同的资源处理大量重复请求。这有助于减少服务器资源的使用, 降低运营成本 - 减少网络流量:
HTTP缓存可以减少不必要的网络流量, 因为浏览器可以从本地缓存中加载资源, 而不必每次都从服务器下载。这有助于减少带宽成本, 尤其是对于大型网站来说 - 提高用户体验: 快速加载的网页提供更好的用户体验, 吸引更多的访问者, 并增加用户留存率。缓存使用户能够更快地访问网站内容, 从而提高了他们的满意度
实际开发中我们有时为了避免因为缓存导致资源没有更新, 常常会简单而粗暴的为资源文件路径添加一个时间戳! 该方式虽然有效, 也能解决实际问题, 但过于粗暴了, 我们完全可以采用更加优雅的方式。本文将对 HTTP 缓存进行一个详细的讲解, 来帮助大家对 HTTP 缓存有一个较深的理解, 帮忙大家在实际项目中设计出更为合理、高效的缓存方案!!
补充(偶然看到一句话, 送给大家): 所有的技术都是为了解决问题而存在的, 在不了解问题情况下强行记忆, 效果肯定是打折扣的!!
本文使用到的
DEMO地址点 这里
一、强缓存
首先在上文我们已经强调了 HTTP 缓存的一个重要性, 那么要想设计一个缓存方案, 最简单的办法就是根据资源加载的时间:
- 首次加载资源时将资源缓存起来
- 然后在指定时间内如果加载同一份资源, 则客户端(浏览器)直接使用缓存数据, 而不向服务器发起任何请求
- 当然如果超时则会发起新的请求获取资源, 然后再次缓存起来

而这种不发起任何请求(没经过服务端), 直接由客户端(浏览器)自行决定是否使用缓存的方案, 则被称为 强缓存!!
1.1 Expires
Expires 响应头, 表示当前获取到的资源的过期时间, 该时间是一个 GMT 时间, 即格林尼治时间!!

当客户端(浏览器)再次获取资源前:
- 如果
存在未到期的缓存资源, 则直接获取缓存的资源, 不发起任何请求!! - 如果
不存在缓存资源或者缓存的资源已过期, 则向服务器发起请求获取资源, 并再次缓存资源

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

但这里其实有一个问题, Expires 时间是由服务端生成的, 这时如果客户端时间跟服务器时间不一致, 就会导致缓存命中的误差!!
所以后面就有了 Cache-Control…
1.2 Cache-Control
Cache-Control 响应头, HTTP/1.1 出现的一个响应头, 它弥补了 Expires 的缺陷:
Expires是直接由服务端给定一个资源过期时间Cache-Control则不同, 服务端只会告诉客户端该资源的有效期! 就比如, 它有一个max-age字段, 当它被设置为10, 则表示当前资源有效期为10秒,10秒过后资源缓存将失效

Cache-Control 相对来说使用起来也更为复杂, 可设置的属性也比较多。当然复杂也说明它可适用于更广泛的复杂场景, 下面我们来看下 Cache-Control 响应头的语法规则:
- 不区分大小写, 但建议使用小写
- 多个指令以逗号分隔
- 具有可选参数, 可以用令牌或者带引号的字符串语法
Cache-Control 可选属性有: 注意 no-cache 和 no-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-revalidate | 与 must-revalidate 作用相同, 但它仅适用于共享缓存(例如代理服务器), 对于私有缓存(本地缓存)该值会被忽略 |
| 重新验证或重新加载 | immutable | 实验版, 表示缓存一直有效, 再也不会发起请求了 |
| 其他 | no-transform | 不允许对资源进行转换或转变, Content-Encoding、Content-Range、Content-Type 等 HTTP 头允许被代理服务修改 |
| 其他 | 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 个头部属性中的优先级是最高的

也许你会奇怪为啥有了 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将是完整的资源内容

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

下面使用 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);

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


猜测: 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

下面使用 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);

同上文, 如果本地缓存有效, 并且服务端状态码为
304,chrome展示状态码也只会是200, 内容为缓存的内容
2.3 补充: If-Unmodified-Since / If-Match
上文提到的几个消息头, 都只是在获取资源(get 请求)情况下生效!! If-Unmodified-Since 和 If-Match 则是在修改内容的情况下生效, 比如 post、put、remove 等请求:
- 当客户端(浏览器)发起请求试图修改资源时, 可以携带上
If-Unmodified-Since(本地资源对应 Last-Modified)或If-Match(本地资源 ETag) - 服务端通过请求头中的
If-Unmodified-Since或If-Match来判断服务端资源是否已经被修改过(当前本地资源是否是最新的) - 如果服务端的资源已经被修改过, 那么服务端直接返回
412(Precondition Failed) 错误, 不处理本次请求 - 相反, 则返回
200! 正常处理请求

三、优先级
- 首先强缓存优先级大于协商缓存, 只有在强缓存失效情况下, 然后才会和服务端建立连接进行协商
- 强缓存中:
Pragma>Cache-Control>Expires - 协商缓存中:
ETag>Last-Modified, 因为ETag更为精准
四、参考
- 30分钟搞懂 HTTP 缓存
- 前端应该知道 HTTP 缓存机制
- 从未如此简单 5 分钟搞懂 HTTP 缓存机制
- 彻底搞懂 HTTP 缓存策略,切记死背概念!
- HTTP 缓存看这一篇就够了
- 图解 HTTP 缓存
- 轻松理解 HTTP 缓存策略
- 面试官: 你懂 HTTP 缓存,那说下浏览器强制刷新是怎么实现的?

相关文章:
初窥 HTTP 缓存
引言 对于前端来说, 你肯定听说过 HTTP 缓存。 当然不管你知不知道它, 对于提高网站性能和用户体验, 它都扮演着重要的角色! 它通过在客户端和服务器之间存储和重用先前获取的资源副本, 来减少网络流量和降低资源加载时间, 从而提升用户体验! 以下是 HTTP 缓存的重要性: 减少…...
yolov8的深度学习环境安装(cuda12.4、ubuntu22.04)
目录 一、先安装基础环境包 1.首先给Ubuntu安装Chrome浏览器(搜索引擎换成百度即可) 2、ubuntu 22.04中文输入法安装 3、安装 terminator 4、安装WPS for Linux 5、安装其它之前需要先安装anaconda 6、安装配置anaconda 7、安装完成anaconda后创建…...
RSA算法和AES算法,哪种更安全
目录 一、RSA (非对称加密算法) 二、AES (对称加密算法) 三、对比总结 四、更安全的选择 五、结合使用:RSA AES RSA 和 AES 是两种不同类型的加密算法,适用于不同的场景,因此它们的安全性不能直接比较,而是取决于具体的应用…...
Vue教程|搭建vue项目|Vue-CLI新版脚手架
一、安装Node环境 安装Node及Npm环境 Node下载地址:Node.js — Run JavaScript EverywhereNode.js is a JavaScript runtime built on Chromes V8 JavaScript engine.https://nodejs.org/en/ 安装完成后,检查安装是否成功,并检查版本,命令如下: node -v npm -v mac@Macd…...
kdump调试分析(适用于麒麟,ubuntu等OS)
1. kdump基本原理 1.1 内核崩溃处理机制 当 Linux 系统内核发生崩溃时,通常会触发 panic,系统停止正常运行。Kdump 在这种情况下: 使用一个备用的内核(称为 crash kernel)来启动最小化的环境。从崩溃的主内核中复制内存内容(转储文件)。将转储文件保存到预定义的存储位…...
houdini肌肉刷pin点的方法
目标:产生gluetoanimation这个属性 主要节点:attribute paint(或者muscle paint) 步骤1: 导入肌肉资产 导入的是rest shape的肌肉 在有侧边栏可以打开display group and attribute list,方便查看group。不同的肌肉块按照muscl…...
JMeter 并发策略-针对准点秒杀场景的压测实现
一、场景的压测实现 1,创建线程组,10并发用户执行5次; 2,创建 Synchronizing Timer 元件,用于同步线程,设置同步元件 Synchronizing Timer 3,创建 http 请求4,创建 view results in table 元件…...
龙迅#LT6912适用于HDMI2.0转HDMI+LVDS/MIPI,分辨率高达4K60HZ,支持音频和HDCP2.2
1. 描述 LT6912是一款高性能的HDMI2.0转HDMI和LVDS和MIPI转换器。 HDMI2.0 输入和输出均支持高达 6Gbps 的数据速率,为4k60Hz视频提供足够的带宽。此外,还支持 HDCP2.2 进行数据解密(无数据 加密)。 对于 LVDS 输出,…...
RBF神经网络预测结合NSGAII多目标优化
目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 RBF神经网络预测结合NSGAII多目标优化 rbf神经网络预测结合nsga2多目标优化 题外话: 多目标优化是指在优化问题中同时考虑多个目标函数的优化过程。在多目标优化中,通常存在多个冲突的目标&am…...
如何看linux系统内核是aarch64 ,还是64-bit
要查看 Linux 系统内核是 aarch64 架构还是 64-bit 架构,可以通过以下几种方法来确认: 方法 1:使用 uname 命令 uname 命令用于显示系统信息。使用以下命令查看系统的架构: uname -m如果输出是 aarch64,说明你的系统…...
如何通过 ADB 安装 xapk
Android开发这么久,今天发现还能这么操作!😂 记录通过ADB安装xapk、apks的两种方式: 1.ADB命令安装使用APK-Splits技术分包的应用程序 这位大佬的方式步骤较为繁琐,不过兼容性应该较好,亲测成功安装。 2.How to install xapk, apks, or multiple-apks via adb? 这个…...
QT:多ui界面显示
文章目录 1.多ui界面添加2.跳转函数3.返回函数4.Qt5源码工程5.模态显示 1.多ui界面添加 最终生成这个目录 2.跳转函数 void MainWindow::on_pushButton_clicked() {//this->setWindowModality(Qt::WindowModal);test1 *t1 new test1();t1->setParentData(this);this-…...
redis cluster 3主3从部署方案
文章目录 1 Redis Cluster 介绍1 Redis cluster 架构2 Redis cluster的工作原理2.1 数据分区2.2 集群通信2.3 集群伸缩2.3.1 集群扩容2.3.2 集群缩容 2.4 故障转移2.4.1 主观下线2.4.2 客观下线 3 Redis Cluster 部署架构说明3.1 部署方式介绍3.2 实战案例:基于Redi…...
前端学习笔记之文件下载(1.0)
因为要用到这样一个场景,需要下载系统的使用教程,所以在前端项目中就提供了一个能够下载系统教程的一个按钮,供使用者进行下载。 所以就试着写一下这个功能,以一个demo的形式进行演示,在学习的过程中也发现了中文路径…...
从技术视角看AI在Facebook全球化中的作用
在全球化日益加深的今天,人工智能(AI)作为一种变革性技术,正在深刻影响全球互联网巨头的发展方向。Facebook作为全球最大的社交媒体平台之一,正通过AI技术突破语言、文化和技术的障碍,推动全球化战略的实现…...
Web 表单开发全解析:从基础到高级掌握 HTML 表单设计
文章目录 前言一、什么是 Web 表单?二、表单元素详解总结前言 在现代 Web 开发中,表单 是用户与后端服务交互的重要桥梁。无论是用户登录、注册、搜索,还是提交反馈,表单都无处不在。在本文中,我们将从基础入手,全面解析表单的核心知识点,并通过示例带你轻松掌握表单开…...
Milvus 2.5:全文检索上线,标量过滤提速,易用性再突破!
01. 概览 我们很高兴为大家带来 Milvus 2.5 最新版本的介绍。 在 Milvus 2.5 里,最重要的一个更新是我们带来了“全新”的全文检索能力,之所以说“全新”主要是基于以下两点: 第一,对于全文检索基于的 BM25 算法,我们采…...
【webrtc】 mediasoup中m77的IntervalBudget及其在AlrDetector的应用
IntervalBudget 用于带宽控制和流量整形 mediasoup中m77 代码的IntervalBudget ,版本比较老IntervalBudget 在特定时间间隔内的比特预算管理,从而实现带宽控制和流量整形。 一。 pacedsender 执行周期: 下一次执行的时间的动态可变的 int64_t PacedSender::TimeUntilNextPr…...
AI数据分析工具(二)
豆包-免费 优点 强大的数据处理能力: 豆包能够与Excel无缝集成,支持多种数据类型的导入,包括文本、数字、日期等,使得数据整理和分析变得更加便捷。豆包提供了丰富的数据处理功能,如数据去重、填充缺失值、转换格式等…...
小米路由mini刷PDCN教程补充
花了10天帮助一个网友解决小米路由刷PDCN做打印服务器失败的过程,经历颇多。特别把中间的一些坑写出来,希望大家不要遇到。 首先网上好多教程写的都不错,很适合小白。推荐如下: 刷breed和PDCN方法: 小米路由器mini刷…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
WordPress插件:AI多语言写作与智能配图、免费AI模型、SEO文章生成
厌倦手动写WordPress文章?AI自动生成,效率提升10倍! 支持多语言、自动配图、定时发布,让内容创作更轻松! AI内容生成 → 不想每天写文章?AI一键生成高质量内容!多语言支持 → 跨境电商必备&am…...
IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
scikit-learn机器学习
# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...
解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
