Chrome Extensions v3 迁移清单

news2025/2/21 21:52:49

img

一、前置问题

1.1为什么需要迁移 v3?

Chrome 计划完全停止 v2 版本维护,后续 v2 版本将无法上架谷歌插件商店,除此之外,未来新版本 Chrome 对于 v2 版本插件的限制会越来越大,比如安全性限制 iframe 嵌套只能通过沙盒模式数据通信传递而不能直接获取数据等等,因此 v2 迁移 v3 是必要的。

1.2 v3 版本带来了什么新特性?

  • 更强的隐私性,这一点在权限配置上会有所体现,权限划分更细腻。
  • 更强的安全性,比如废弃 eval 方法,禁止加载运行远程仓库代码
  • 更佳的性能,比如 background 被替换为 service workers,它不会持久运行
  • 整合和调整了部分 API ,更符合未来的发展等等。

1.3 v2 迁移 V3 我需要做什么?

主要是四个方向的改动:

  • manifest 配置更新
  • background 迁移 Service Worker
  • API 变更
  • 安全调整

以下是具体需要做的事情。

二、manifest 更新清单

2.1 manifest.json版本号

manifest 版本号需要改为 3。

// v2
{
  ...
  "manifest_version": 2
  ...
}
// v3
{
  ...
  "manifest_version": 3
  ...
}

2.2 废弃 persistent

persistent 用于决定 Chrome extensions 是否开启常驻后台,由于 v3 版本 background 迁移 service worker 后后台已经做不到常驻,此属性只能作废,删掉就好。

2.3 更新主机权限

在Manifest V2 中,有两种方法为你的api或任何主机获得权限,要么在 permissions 数组或 optional_permissions 数组。

而 v3 的权限粒度划分会更细腻,不会像之前权限一把梭,所以像主机访问权限配置需要单独添加到 host_permissions 中:

// v2
{
  "permissions": [
    "tabs",
    "bookmarks",
    "https://www.blogger.com/", // 之前主机权限都在 permissions
  ],
  "optional_permissions": [
    "unlimitedStorage",
    "*://*/*",
  ]
}
// v3
{
  "permissions": [
    "tabs",
    "bookmarks"
  ],
  "optional_permissions": [ // 单独配置主机权限
    "unlimitedStorage"
  ],
  "host_permissions": [
    "https://www.blogger.com/",
  ],
  "optional_host_permissions": [// 单独配置主机权限
    "*://*/*",
  ]
}

2.4 Background 迁移 Service Worker

V3 使用 Service Worker 取代了 Background,这里包含两个层面的意思,第一是配置字段变了(见下方代码),第二是 Service Worker 不再像之前的 Background 能做到一直在后台运行,这点我们后面细说。

// v2
{
    ...,
    "background": {
        "scripts": ["background.js"],
        "persistent": false
      },
    ...
}
// v3
{
    ...,
    "background": {
        "service_worker": "background.js" // 字段变了
      	// 删了 persistent
      },
    ...
}

2.5 更新 web_accessible_resources 字段

web_accessible_resources 用于指定哪些资源文件可以被 web 页面访问和加载,但在 v2 时也是一把梭,基本一次配置哪哪的网页都能访问,同样在 v3 此字段改为资源与匹配的对象形式,看代码就懂了:

// v2
{
  ...
  "web_accessible_resources": [
    "images/*",
    "style/extension.css",
    "script/extension.js"
  ],
  ...
}
// v3
{
  ...
    "web_accessible_resources": [
    {
      "resources": [
        "images/*"
      ],
      "matches": [
        "*://*/*"
      ]
    },
    {
      "resources": [ // 指定资源
        "style/extension.css",
        "script/extension.js"
      ],
      "matches": [ // 谁可以访问
        "https://example.com/*"
      ]
    }
  ],
  ...
}

2.6 合并 browser_action 与 page_action 为 action

// v2
{
  "browser_action": {},
  "page_action": {}
}

// v3 直接合并成一个即可
{
  "action": {}
}

2.7 content_security_policy 需要从 string 改为对象配置

content_security_policy 用于定义加载和执行内容的安全策略,在 v3 版本你需要通过对象的形式来做配置:

// v2
"content_security_policy": "script-src 'self' 'unsafe-eval' https://cdn.lr-in-prod.com; object-src 'self'"

// v3
"content_security_policy": {
  "extension_pages": "script-src 'self'; object-src 'self'",
  "sandbox": "sandbox allow-same-origin",
  "web_accessible_resources": "https://cdn.lr-in-prod.com"
}

需要注意的是,v3 处于安全考虑,不再允许执行 eval,所以上方代码中 unsafe-eval 在 v3 就没什么意义了。

三、 background 迁移 Service Worker

我们在 manifest 更新提到 background 迁移 Service Worker 需要更新 manifest 中的字段名,当然除了 key 变了之外, Service Worker 还会有一些本质的区别。避免大家混淆,Service Worker 和 v2 的 background 还是同一个文件,只是现在定义,使用场景都存在部分差异,接下来细说变化。

3.1 Service Worker 不再支持 DOM 访问。

之前写在 background 的关于 dom 操作代码需要移出此文件,现有的 Service Worker 更适合用于做消息推送,时间监听之类的活。

当然,如果你非要在 Service Worker 使用 DOM ,你可以将消息从 Service Worker 发送到页面脚本,然后在页面脚本中执行相应的 DOM 操作。

第二种办法就是通过 Offscreen API 创建离屏文档,在离屏文档中进行 DOM 的操作。简单理解就是插件单独开辟一个虚拟环境用于你来操作 DOM, 比如:

// manifest.json
"permissions": ["offscreen"]

// offscreen.html
<script src="offscreen.js"></script>

// offscreen.js
let textEl = document.querySelector('#text');
textEl.value = data;
textEl.select();
document.execCommand('copy');

// 在 Service Worker 中创建离屏文档
chrome.offscreen.createDocument({
  url: chrome.runtime.getURL('offscreen.html'),
  reasons: ['YOUR_REASON'],
  justification: 'YOUR_JUSTIFICATION',
});

但需要注意的是离屏文档使用插件自身 API 又有不少限制,具体可以查看文档 chrome.offscreen

3.2 Service Worker 不支持 Window 调用

v3 的 Service Worker 不支持调用 Window,因此 localStorage 直接用不了,注意只是在 Service Worker 中,其它文件你想用还是正常用,对应的我们需要更换为 chrome.storage.local 或者其它存储方式。

3.3 Service Worker 不再支持后台常驻运行

在 v2 版本由于 background 支持后台持久运行,我们可能直接在 background 定义持久变量,如下代码你希望统计事件派发次数:

let num = 0;
chrome.runtime.onMessage.addListener((message) => {
    num++;
    console.log(count);
});

但由于 v3 不再持久运行,那么上述代逻每次被激活 num 会不断被重置为 0,如果你还需要达到上述效果得结合本地缓存:

chrome.runtime.onMessage.addListener((message) => {
  const count = await chrome.storage.local.get(['num']);
    num++;
    chrome.storage.local.set({'num': num})
});

3.4 保证 Service Worker 同步注册事件监听

在 Manifest V3 中,背景页面已被替换为 Service Worker。与 Manifest V2 不同,Service Worker 是事件驱动的,并且在事件被派发时会重新初始化。这意味着在 Service Worker 中异步注册事件监听器的方式可能无法保证正常工作,因为在事件派发时,监听器可能尚未注册完毕。

比如在 v2:

chrome.storage.local.get(["badgeText"], ({ badgeText }) => {
  chrome.browserAction.setBadgeText({ text: badgeText });
  // 异步注册
  chrome.browserAction.onClicked.addListener(handleActionClick);
});

在 v3 请保证注册同步:

chrome.action.onClicked.addListener(handleActionClick);

chrome.storage.local.get(["badgeText"], ({ badgeText }) => {
  chrome.action.setBadgeText({ text: badgeText });
});

3.5 v3 Service Worker 以及整个插件都不再建议 XMLHttpRequest

在 Manifest V3 中,由于安全性和隔离性的考虑, Service Worker 禁止使用 XMLHttpRequest(),其它地方不建议使用 XMLHttpRequest。总体来讲,建议将后台脚本中对 XMLHttpRequest() 的调用替换为使用全局的 fetch() 来执行网络请求。

const xhr = new XMLHttpRequest();
console.log('UNSENT', xhr.readyState); 

xhr.open('GET', '/api', true);
console.log('OPENED', xhr.readyState);

xhr.onload = () => {
    console.log('DONE', xhr.readyState);
};
xhr.send(null);

V3 替换为 fetch:

const response = await fetch('https://www.example.com/greeting.json'');
console.log(response.statusText);

说直白点,如果你之前插件在 background 使用了 axios(基于 XMLHttpRequest 的封装),那么此时你必须把 background 的请求替换成 fetch,考虑到 fetch 与 XMLHttpRequest 存在部分差异,比如 fetch 会认为 404 500 错误码都不是 reject,以及 fetch 不会像 axios 直接集成请求响应拦截,所以如果你要替换一个使用上等价于 axios 的库,这里我推荐 ky,它解决了上述我说的对于错误码的处理,retry 封装,请求响应拦截封装等等。

(关于 axios 与 ky 的使用差异,后续我单独提供一篇文档)

3.6 使用 Alarms API 代替定时器

同理,由于 Service Worker 不再常驻执行,以前我们可能通过定时器异步来更改插件图标或其它操作,这都可能因为 Service Worker 释放导致定时器无法按预期执行,使用 Alarms 代替定时器;需要注意的除 Service Worker 外定时器还是随便你使用。

// v2
const TIMEOUT = 3 * 60 * 1000; 
setTimeout(() => {
  chrome.action.setIcon({
    path: getRandomIconPath(),
  });
}, TIMEOUT);

// v3
async function startAlarm(name, duration) {
  await chrome.alarms.create(name, { delayInMinutes: 3 });
}

chrome.alarms.onAlarm.addListener(() => {
  chrome.action.setIcon({
    path: getRandomIconPath(),
  });
});

四、API 更新

4.1 tabs.executeScript() 替换为 scripting.executeScript()

使用 scripting.executeScript() 需要在 manifest 配置权限

"permissions": ["activeTab", "scripting"],

注入脚本方式代码层面的代码变化,比如 tabID 不再单独作为参数,files 支持传递多个文件,格式也变成了一个数组:

// v2
async function getCurrentTab() {/* ... */}
let tab = await getCurrentTab();

chrome.tabs.executeScript(
  tab.id,
  {
    file: 'content-script.js'
  }
);

// v3
async function getCurrentTab()
let tab = await getCurrentTab();

chrome.scripting.executeScript({
  target: {tabId: tab.id},
  files: ['content-script.js']
});

如果是直接执行代码,变化如下:

// v2
chrome.tabs.executeScript(
  tab.id,
	{
  	code: alert("Hello, World!")
	}
);

// v3
chrome.scripting.executeScript({
  target: { tabId: tab.id },
  function: () => {
    alert("Hello, World!");
  },
});

4.2 tabs.insertCSS() tabs.removeCSS() 替换为 scripting.insertCSS() scripting.removeCSS()

在 Manifest V2 中,我们使用 chrome.tabs.insertCSS 方法来向标签页注入 CSS 样式,而在 Manifest V3 中,这些方法已经从 tabs API 移到了 scripting API。这个迁移需要更新清单文件中的权限,以及修改代码。

同理,使用 scripting.insertCSS 也需要配置权限

"permissions": [
  "activeTab", // 如果你只需要在当前激活的标签页中注入 CSS
  "scripting"  // 添加 scripting 权限
],

注入样式文件前后对比:

// v2
chrome.tabs.insertCSS(tabId, injectDetails, () => {
  file: 'style.css'
});

// v3
const insertPromise = await chrome.scripting.insertCSS({
  files: ["style.css"],
  target: { tabId: tab.id }
});
// 剩余的代码

注入字符串的前后对比:

// v2
chrome.tabs.insertCSS(tabId, {
  code: 'body { background-color: lightblue; }'
}, () => {
  // 在注入样式后执行的回调
});

// v3 支持 promise 取代回调的写法,当然你也能继续用回调
const insertPromise = chrome.scripting.insertCSS({
  target: { tabId: tab.id },
  css: 'body { background-color: lightblue; }'
});

4.3 更推荐 promise 回调用法取代回调

上方例子在注入样式文件 v2 采用回调形式处理注入之后的行为,v3 更建议 promise 用法,当然这只是建议并不是硬性要求,保留原有回调并不会出错。

4.4 合并 Browser Actions and Page Actions 为 Actions

这个在 manifest 迁移已经提了一次,除了配置合并外,这两个 API 也被合并为 actions

// v2
chrome.browserAction.onClicked.addListener(tab => { ... });
chrome.pageAction.onClicked.addListener(tab => { ... });
                                                
// v3
chrome.action.onClicked.addListener(tab => { ... });

4.5 替换 v2 background 上下文获取的函数

在 Manifest V3 中,不同的扩展上下文只能通过消息传递与 service worker 进行交互。因此,你需要替换那些期望与后台上下文交互的调用,具体包括以下几个:

  1. chrome.runtime.getBackgroundPage(): 这个函数通常用于获取后台页(background page)的引用,以便与后台页通信。在 Manifest V3 中,由于没有后台页的概念,你需要使用消息传递来与 service worker 通信,而不是直接获取后台页的引用。
  2. chrome.extension.getBackgroundPage(): 类似于 chrome.runtime.getBackgroundPage(),这个函数也用于获取后台页的引用,而在 Manifest V3 中,同样需要改用消息传递来实现与 service worker 通信。
  3. chrome.extension.getExtensionTabs(): 这个函数用于获取扩展的标签页信息。在 Manifest V3 中,标签页的概念发生了变化,因此需要采用不同的方法来获取相关信息。

第一和第二点好理解,毕竟 service worker 不再常驻,不能直接获取 background 直接用里面的变量,需要改为通信的形式。

关于第三点,因为 Manifest V3 引入了一些重大的更改,包括对标签页(tabs)的管理方式。如果你需要获取有关标签页的信息,你可以使用 chrome.tabs API。

// 获取当前标签页信息:
chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
  // tabs[0] 包含了当前标签页的信息
  console.log(tabs[0]);
});

// 获取所有标签页信息:
chrome.tabs.query({}, function(tabs) {
  // tabs 包含了所有标签页的信息
  console.log(tabs);
});

// 更新标签页的URL:
chrome.tabs.update(tabId, { url: 'https://new-url.com' });

// 打开一个新的标签页:
chrome.tabs.create({ url: 'https://example.com' });

4.6 替换不再支持的 API(需要全局搜索对应替换)

以下方法或者属性需要在 v3 进行替换:

v2 属性或方法需要替换为
chrome.extension.connect()chrome.runtime.connect()
chrome.extension.connectNative()chrome.runtime.connectNative()
chrome.extension.getExtensionTabs()chrome.extension.getViews()
chrome.extension.getURL()chrome.runtime.getURL()
chrome.extension.lastError当方法返回promise 使用 promise.catch()
chrome.extension.onConnectchrome.runtime.onConnect
chrome.extension.onConnectExternalchrome.runtime.onConnectExternal
chrome.extension.onMessagechrome.runtime.onMessage
chrome.extension.onRequestchrome.runtime.onRequest
chrome.extension.onRequestExternalchrome.runtime.onMessageExternal
chrome.extension.sendMessage()chrome.runtime.sendMessage()
chrome.extension.sendNativeMessage()chrome.runtime.sendNativeMessage()
chrome.extension.sendRequest()chrome.runtime.sendMessage()
chrome.runtime.onSuspend(background中使用)不再支持在 service worker 使用,请用 beforeunload 代替
chrome.tabs.getAllInWindow()chrome.tabs.query()
chrome.tabs.getSelected()chrome.tabs.query()
chrome.tabs.onActiveChangedchrome.tabs.onActivated
chrome.tabs.onHighlightChangedchrome.tabs.onHighlighted
chrome.tabs.onSelectionChangedchrome.tabs.onActivated
chrome.tabs.sendRequest()chrome.runtime.sendMessage()
chrome.tabs.Tab.selectedchrome.tabs.Tab.highlighted

五、安全改进

5.1 禁用 evel 等字符串执行方法

V3 出于安全考虑,不再允许执行一些危险的 JavaScript 操作,比如字符相关的方法 executeScripteval()以及 new Function等方法。

eval()方法大家走知道能强制执行字符串,这里不过多解释,关于 new Function 创建函数同样能以字符串的形式定义函数体,同理也被禁止。

关于executeScript其实上文scripting.executeScript我们已经给了例子,这里再贴个例子:

// v2 不再推荐
chrome.tabs.executeScript(
  tab.id,
	{
  	code: alert("Hello, World!")
	}
);

// 不允许使用 eval
chrome.scripting.executeScript({
  target: { tabId: tab.id },
  function: () => {
    eval('alert("This is unsafe!")');
  }
});

// v3 正确用法
chrome.scripting.executeScript({
  target: { tabId: tab.id },
  function: () => {
    alert("Hello, World!");
  },
});

// 或者把代码部分单独定义方法
const fn = () => alert("Hello, World!");
chrome.scripting.executeScript({
  target: { tabId: tab.id },
  function: fn,
});

当然有版本绕过 v3 报错强制使用 eval,比如开启沙盒模式,在沙盒中使用 eval,再通过与外界通信,但是非必要不建议这么做。

5.2 不再支持加载和执行远程托管代码(这个很头疼)

v3 出于安全考虑,不能直接引用或执行托管在远程服务器上的 JavaScript 代码,防止恶意代码的执行,比如:

  • 不允许从服务器上动态拉取 JavaScript 文件并执行。
  • 不允许通过 CDN 远程加载代码。

说通俗点,你需要执行的代码都应该属于插件代码自身的一部分,假设插件使用到了 react,一种解决办法是我们本地开发 npm react 后,再打包插件时应该将 react 源码也一起打包进去。

另一种办法,就是直接将 cdn 代码直接拷贝到本地,然后全局通过 scripting.executeScript 注入。

5.3 安全策略配置值调整

这一点在 manifest 提过一次,除了 content_security_policy 由 v2 字符串变成 v3 对象之外,“script-src”、“object-src” 和 “worker-src” 指令,只有以下四个值是被允许的:

  1. self: 这表示只允许从与扩展自身相关的源加载脚本、对象或 Worker 脚本。
  2. none: 这表示不允许加载任何脚本、对象或 Worker 脚本。
  3. wasm-unsafe-eval: 这表示允许加载 WebAssembly 模块,但禁止执行不安全的 eval 操作。
  4. 仅适用于未打包的扩展:localhost 源,包括 http://localhosthttp://127.0.0.1 或这些域上的任何端口。

所以在 manifest 我们强调了像 unsafe-eval 这种直接废弃了,毕竟不支持 eval 执行了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1088573.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用gdb调试core文件和breakpad的简单使用

1 core文件的配置 默认情况下&#xff0c;如果程序崩溃了是不会生成core文件的&#xff0c;因为生成core文件受到系统ulimit配置的影响。 ulimit -c是core文件的大小&#xff0c;默认为0&#xff0c;因此&#xff0c;就不会生成core文件&#xff0c;因此&#xff0c;为了能够…

【DRAM存储器十六】DDR2介绍-DDR到DDR2的变化、DDR2框图详解、模式寄存器

&#x1f449;个人主页&#xff1a;highman110 &#x1f449;作者简介&#xff1a;一名硬件工程师&#xff0c;持续学习&#xff0c;不断记录&#xff0c;保持思考&#xff0c;输出干货内容 参考资料&#xff1a;《镁光DDR数据手册》 目录 DDR2 SDRAM介绍 DDR2相对DDR的变化…

C++day07(auto、lambda、类型转换、STL、文件操作)

今日任务 试编程&#xff1a; 封装一个学生的类&#xff0c;定义一个学生这样类的vector容器, 里面存放学生对象&#xff08;至少3个&#xff09; 再把该容器中的对象&#xff0c;保存到文件中。 再把这些学生从文件中读取出来&#xff0c;放入另一个容器中并且遍历输出该容…

go-gin-api 本地部署调试问题总结

1.告警邮箱设置 保存后会自动将配置信息保存在fat_configs.toml 文件中&#xff1b; 可能出现问题&#xff1a;报错 550和 anth 问题&#xff0c;说明你的邮箱配置有问题&#xff08;密码或者授权码&#xff09;&#xff1b; 2.生成数据表curd 执行结果报错 exec: “gormge…

三防PDA手持终端开发板-联发科MTK6765平台安卓主板方案

三防手持终端安卓主板方案采用了联发科12nm八核MT6765处理器&#xff0c;配备4G64GB内存(可选配6GB256GB)&#xff0c;并搭载最新的Android 10.0操作系统。该方案支持许多功能&#xff0c;包括高亮显示屏、高清摄像头、NFC、3A快速充电、1D/2D扫描(可选配)、高精度定位(可选配)…

Torch生成类激活图CAM

import torch from torch.nn import functional as F from torchvision import models, transforms from PIL import Image import os os.environ[KMP_DUPLICATE_LIB_OK]TRUE# 加载经过训练的 ResNet 模型 model models.resnet50(pretrainedTrue) model.eval()# 载入图像并进行…

NFT Insider111:The Sandbox 推出乐天世界主题公园元宇宙,Aavegotchi 与 CARV达成合作

引言&#xff1a;NFT Insider由NFT收藏组织WHALE Members、BeepCrypto联合出品&#xff0c;浓缩每周NFT新闻&#xff0c;为大家带来关于NFT最全面、最新鲜、最有价值的讯息。每期周报将从NFT市场数据&#xff0c;艺术新闻类&#xff0c;游戏新闻类&#xff0c;虚拟世界类&#…

CSwin Transformer 学习笔记

Cswin提出了上图中使用交叉形状局部attention&#xff0c;为了解决VIT模型中局部自注意力感受野进一步增长受限的问题&#xff0c;同时提出了局部增强位置编码模块&#xff0c;超越了Swin等模型&#xff0c;在多个任务上效果SOTA&#xff08;当时的SOTA&#xff0c;已经被SG Fo…

滑动窗口算法题

更新结果 1、判断条件成立后更新结果 2、入窗口后即可更新结果 判断&#xff1a; 出窗口后状态更新&#xff0c;循环回去再判断。 1、长度最小的子数组 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台

【C++STL基础入门】排序和遍历容器

文章目录 前言使用前须知头文件 一、for_each算法1.1 for_each是什么1.2 函数原型1.3 示例代码1:将容器中的每个元素打印出来1.4 示例代码2&#xff1a;将容器中的每个字符串转换为大写形式 二、sort算法2.1 sort算法是什么&#xff1f;2.2 函数原型2.3 示例代码1&#xff1a;按…

Win10找不到hosts文件的解决方案

正常情况下&#xff0c;Windows10系统的C:\Windows\System32\drivers\etc目录下应该有hosts文件&#xff0c;但偏偏有些电脑没有&#xff0c;哪怕你打开了查看“隐藏的项目”也没见到hosts文件&#xff0c;如下&#xff1a; 解决方案 1、先点击查看&#xff0c;再点击选项&…

红队专题-工具Fscan

红队专题 招募六边形战士队员简介主要功能 ubuntu 安装windows 安装常用命令&#xff1a;项目框架源文件common目录Plugins目录Webscan目录爆破插件Webtitle函数webpoc扫描类型common.Scantype 免杀源码特征 参考链接 招募六边形战士队员 一起学习 代码审计、安全开发、web攻防…

有哪些免费的PPT模板网站,推荐这6个PPT模板免费下载网站!

混迹职场的打工人&#xff0c;或是还在校园的学生党&#xff0c;在日常的工作汇报或课程作业中&#xff0c;必然少不了PPT的影子&#xff0c;而每当提到做PPT&#xff0c;许多人首先会想到&#xff1a;有哪些免费的PPT模板下载网站&#xff1f; 本着辛苦自己&#xff0c;造福所…

(vue)el-select根据下拉框显示隐藏的visible-change的事件使用

(vue)el-select根据下拉框显示隐藏的visible-change的事件使用 <el-select v-model"value1"multiple:multiple-limit"2"placeholder"请选择" visible-change"visibleChange" ><el-option...></el-option> </el-s…

【C++STL基础入门】list基本使用

文章目录 前言一、list简介1.1 list是什么1.2 list的头文件 二、list2.1 定义对象2.2 list构造函数2.3 list的属性函数 总结 前言 STL&#xff08;Standard Template Library&#xff09;是C标准库的一个重要组成部分&#xff0c;提供了一套丰富的数据结构和算法&#xff0c;可…

【算法练习Day19】二叉搜索树的最近公共祖先二叉搜索树中的插入操作删除二叉搜索树中的节点

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 二叉搜索树的最近公共祖先叉…

MS5611的ZYNQ驱动试验之一 分析

0&#xff0c;MS5611框图 1&#xff0c;原理图 项目需要用到MS5611气压计模块&#xff0c;原理图很简单明了&#xff0c;如下&#xff1a; 这里PS接GND是SPI接口模式&#xff0c;PS接VDD是I2C接口模式。我在设计原理图时候直接设置成了SPI模式&#xff0c;当然这个SPI不是纯粹意…

ubuntu 22.04.3 live server图文安装流程

备注&#xff1a;以下操作全用键盘&#xff0c;tab切换&#xff0c;enter确认&#xff0c;方向键移动&#xff1b; 一、安装操作系统 1、 选择安装&#xff0c;第一个&#xff1b; 2、选择语言&#xff0c;这里只能选择英语&#xff0c;无中文&#xff1b; 3、继续而不更新 4、…

springcloud笔记(7)-限流降级Sentinel

官方文档&#xff1a;概述 | Spring Cloud Alibaba basic-api-resource-rule | Sentinel (sentinelguard.io) Sentinel是SpringCloudAlibaba的组件。 sentinel的功能 introduction | Sentinel 流量控制 熔断降级&#xff1a;降低调用链路中的不稳定资源 系统负载保护&am…

什么是接口自动化?为什么要做?和怎么做接口自动化?

服务端接口测试介绍 什么是服务端&#xff1f; 一般所说的服务端是指为用户在 APP 或 PC 使用的互联网功能提供数据服务的背后的一切。以天猫精灵智能音箱系列的产品链路为例&#xff0c;服务端便是网关&#xff08;包括网关在内&#xff09;之后的链路。 什么是接口&#xf…