Chrome Extensions v3 迁移清单
一、前置问题
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 进行交互。因此,你需要替换那些期望与后台上下文交互的调用,具体包括以下几个:
chrome.runtime.getBackgroundPage()
: 这个函数通常用于获取后台页(background page)的引用,以便与后台页通信。在 Manifest V3 中,由于没有后台页的概念,你需要使用消息传递来与 service worker 通信,而不是直接获取后台页的引用。chrome.extension.getBackgroundPage()
: 类似于chrome.runtime.getBackgroundPage()
,这个函数也用于获取后台页的引用,而在 Manifest V3 中,同样需要改用消息传递来实现与 service worker 通信。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.onConnect | chrome.runtime.onConnect |
chrome.extension.onConnectExternal | chrome.runtime.onConnectExternal |
chrome.extension.onMessage | chrome.runtime.onMessage |
chrome.extension.onRequest | chrome.runtime.onRequest |
chrome.extension.onRequestExternal | chrome.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.onActiveChanged | chrome.tabs.onActivated |
chrome.tabs.onHighlightChanged | chrome.tabs.onHighlighted |
chrome.tabs.onSelectionChanged | chrome.tabs.onActivated |
chrome.tabs.sendRequest() | chrome.runtime.sendMessage() |
chrome.tabs.Tab.selected | chrome.tabs.Tab.highlighted |
五、安全改进
5.1 禁用 evel 等字符串执行方法
V3 出于安全考虑,不再允许执行一些危险的 JavaScript 操作,比如字符相关的方法 executeScript
、eval()
以及 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” 指令,只有以下四个值是被允许的:
self
: 这表示只允许从与扩展自身相关的源加载脚本、对象或 Worker 脚本。none
: 这表示不允许加载任何脚本、对象或 Worker 脚本。wasm-unsafe-eval
: 这表示允许加载 WebAssembly 模块,但禁止执行不安全的 eval 操作。- 仅适用于未打包的扩展:
localhost
源,包括http://localhost
、http://127.0.0.1
或这些域上的任何端口。
所以在 manifest 我们强调了像 unsafe-eval
这种直接废弃了,毕竟不支持 eval 执行了。
相关文章:
Chrome Extensions v3 迁移清单
一、前置问题 1.1为什么需要迁移 v3? Chrome 计划完全停止 v2 版本维护,后续 v2 版本将无法上架谷歌插件商店,除此之外,未来新版本 Chrome 对于 v2 版本插件的限制会越来越大,比如安全性限制 iframe 嵌套只能通过沙盒…...
TCP/IP(十二)TCP的确认、超时、重传机制
一 TCP的确认应答机制 确认应答机制: 每次收到数据 都会 给对端发送一个应答报文(ACK) ① 带重传的肯定确认 确认机制: 超时 重传的 肯定 确认 --> 完成了两个作用,或者说有两个含义1、肯定[正确] 确认小结: 我的确认信息是针对正确数据做确认,而不是错误…...
C/C++陷阱——临时变量的产生和特性
C/C陷阱——临时变量的产生和特性 在学习C常引用时,有这样一段代码引起了我的注意: int a 1; double& b a;当我编译这段代码时,竟然报错了: 按理来说,初始化引用时不能涉及权限的放大(如用const in…...
【音视频|ALSA】SS528开发板编译Linux内核ALSA驱动、移植alsa-lib、采集与播放usb耳机声音
😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀 🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C、数据结构、音视频🍭 🤣本文内容🤣&a…...
C/C++基础讲解(一百三十一)之经典篇(信息合并/平均分数存储)
C/C++基础讲解(一百三十一)之经典篇(信息合并/平均分数存储) 程序之美 前言 很多时候,特别是刚步入大学的学子们,对于刚刚开展的计算机课程基本上是一团迷雾,想要弄明白其中的奥秘,真的要花费一些功夫,我和大家一样都是这么啃过来的,从不知到知知,懵懂到入门,每一步…...
【ROS】使用vscode浏览navigation2源码时,提示:没有那个文件或目录
【ROS】郭老二博文之:ROS目录 1、问题描述 使用vscode浏览navigation2源码时,头文件下面有波浪线,并提示:没有那个文件或目录。比如没有:geometry_msgs/msg/polygon.h 错误信息: 无法打开源文件 “geometry_msgs/msg/polygon.h” (dependency of “nav2_controller/co…...
ARM-day9作业
main.c: #include "uart.h"#include "key_it.h"int main(){char c;char *s;uart4_init(); //串口初始化//中断初始化key_it_config();key3_it_config();//完成GPIO相关初始化all_led_init();//风扇初始化fs_init();//蜂鸣器初始化fmq_init();while(1){…...
ORA-00600: internal error code, arguments
通过rman将11g异机升级到19c时,应用归档时报错,报错如下 RMAN> recover database ; Starting recover at 2023-10-15 21:10:02 allocated channel: ORA_DISK_1 channel ORA_DISK_1: SID5776 device typeDISK starting media recovery media recove…...
C#里氏替换
在C#中,里氏替换原则是面向对象编程中的一个重要原则,它是关于继承和多态性的概念。 里氏替换原则的定义是:如果S是T的子类型(或者T是S的基类型),那么程序中任意使用T类型的地方都可以替换为S类型而不会产…...
Java-使用sqlSessionTemplate实现批量更新-模拟mybatis 动态sql
环境准备(非核心方法) 创建表 创建表的sql(下表是基于Oracle创建的) CREATE TABLE "SYSTEM"."STUDENT" ("ID" NUMBER(10, 0),"NAME" VARCHAR2(20 BYTE),"ADDRES" CLOB,PRIMARY KEY ( …...
Eslint配置 Must use import to load ES Module(已解决)
最近在配置前端项目时,eslint经常会碰到各种报错(灰常头疼~) Syntax Error Error No ESLint configuration found.Syntax Error: Error: D:\dmq\dmq-ui.eslintrc.js: Environment key “es2021” is unknown at Array.forEach ()error in ./…...
正向代理(流量代理)
文章目录 正向代理与反向代理流量转发工具环境准备reGeorg 正向代理与反向代理 正向代理是客户端和其他所有服务器(重点:所有)的代理者 反向代理是客户端和所要代理的服务器之间的代理。 流量转发工具 需要放在拿到shell的服务器上可使用 …...
易天光通信推出100G BIDI ER光模块最新解决方案
随着数字信息时代的快速发展,网络通信技术的迅猛进步成为推动科技创新和产业升级的重要引擎之一。作为光通信行业的新秀,近期易天光通信推出了全新的100G BIDI ER1 Lite光模块和100G BIDI LR1 Lite光模块,助力崭新的未来网络建设。 易天光通…...
Flask框架配置celery-[1]:flask工厂模式集成使用celery,可在异步任务中使用flask应用上下文,即拿即用,无需更多配置
一、概述 1、celery框架和flask框架在运行时,是在不同的进程中,资源是独占的。 2、celery异步任务如果想使用flask中的功能,如orm,是需要在flask应用上下文管理器中执行orm操作的 3、使用celery是需要使用到中间件的࿰…...
合并二叉树
题目链接 合并二叉树 题目描述 注意点 如果两个节点重叠,那么将这两个节点的值相加作为合并后节点的新值;否则,不为 null 的节点将直接作为新二叉树的节点 解答思路 先序遍历二叉树,将重叠部分节点值相加作为新节点的值&…...
Sanic——Python函数变成API的神器
今天给大家介绍一个超好用的框架,迅速将Python函数变成API,它就是最近越来越火的异步Web框架Sanic。 1. Sanic简介 Sanic 是 Python3.7 Web 服务器和 Web 框架,旨在提高性能。它允许使用 Python3.5 中添加的async/await语法,这使…...
Windows连接不上VMware,ping不通的问题
文章目录 防火墙问题Windows和虚拟机下的ip不一致导致的问题VMware Network Adapter (适配器)丢失的问题参考文档 防火墙问题 防火墙默认不会拦截ping命令,除非你个人设置了Linux防火墙Centos7的常用命令关闭防火墙 systemctl stop firewalld #停止Windows和虚拟机…...
24、Flink 的table api与sql之Catalogs(java api操作数据库、表)-2
Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…...
【MySQL】深入了解索引的底层逻辑结构
文章目录 主键排序一. InnoDB的索引结构1. 单个page2. 多个page 二. 为什么选择B树三. 聚簇索引和非聚簇索引结束语 主键排序 我们创建一个user表,并乱序插入数据 mysql> create table if not exists user(-> id int primary key,-> age int not null,-&…...
Android之SpannableString使用
文章目录 前言一、效果图二、实现代码总结 前言 在开发中,往往有些需求是我们不愿意遇到的,但是也不得不处理的事情,比如一段文案,需要文案中某些文字变颜色或者点击跳转,所以简单写了几句代码实现,没什么…...
【Python】Python求均值、中值和众数
Python求均值、中值和众数 我们将讨论如何使用描述性统计数据进行数据分析,包括: 均值——一组值的平均值; 中值——当所有值按顺序排列时的中间值; 众数——最常出现的值。 以上这些都是集中趋势度量,每种都会产生一个值来表示一组值中的“…...
NPM 常用命令(十二)
目录 1、npm unpublish 1.1 使用语法 1.2 描述 2、npm unstar 2.1 使用语法 3、npm update 3.1 使用语法 3.2 描述 3.3 示例 插入符号依赖 波浪号依赖 低于 1.0.0 的插入符号依赖 子依赖 更新全局安装的包 4、npm version 4.1 使用语法 5、npm view 5.1 使用语…...
数据在内存中的存储(2)
文章目录 3. 浮点型在内存中的存储3.1 一个例子3.2 浮点数存储规则 3. 浮点型在内存中的存储 常见的浮点数: 3.14159 1E10 ------ 1.0 * 10^10 浮点数家族包括: float、double、long double 类型 浮点数表示的范围:float.h中定义 3.1 一个例…...
软件工程与计算总结(十三)详细设计中的模块化与信息隐藏
一.模块化与信息隐藏思想 1.设计质量 好的设计要着重满足以下3方面:可管理性、灵活性、可理解性好的设计需要侧重于间接性和可观察性——简洁性使得系统模块易于管理(理解和分解)、开发(修改与调试)和复用。实践者都…...
RF学习——器件的非线性失真分析
在大信号激励下的射频系统 在电路中,如果激励信号的幅度不可忽视,那么就会产生非线性失真。如二极管,晶体管等电路元件的特性在大信号激励下回变得非线性,输入和输出的形状不同,产生失真。 在功率放大器PA中,随着传输给负载的功率增大而迅速增大,传递功率的规格要始终考…...
SUB-1G SOC芯片DP4306F 32 位 ARM Cortex-M0+内核替代CMT2380F32
DP4306F是一款高性能低功耗的单片集成收发机,集成MO核MCU,工作频率可覆盖200MHiz^ 1000MHz。 支持230/408/433/470/868/915频段。该芯片集成了射频接收器、射频发射器、频率综合器、GFSK调制器、GFSK解调器等功能模块。通过SPI接口可以对输出功率、频道选…...
接收请求地址下载并输出文件流实现
代码: import httpxfrom datetime import datetime from io import BytesIO from fastapi.responses import StreamingResponse@router.get("/download", tags=["下载"]) async...
【iOS】——用单例类封装网络请求
文章目录 一、JSONModel1.JSONModel的简单介绍2.JSONModel的使用 二、单例类和Block传值 一、JSONModel 1.JSONModel的简单介绍 JSONModel一个第三方库,这个库用来将网络请求到的JSON格式的数据转化成Foundation框架下的Model类的属性,这样我们就可以直…...
再学Blazor——概述
简介 Blazor 是一种 .NET 前端 Web 框架,同时支持服务器端呈现和客户端交互性。 使用 C# 语言创建丰富的交互式 UI共享前后端应用逻辑可以生成混合桌面和移动应用受益于 .NET 的性能、可靠性和安全性需要有 HTML、CSS、JS 相关基础(开发 UI 框架的话&a…...
Ceph运维笔记
Ceph运维笔记 一、基本操作 ceph osd tree //查看所有osd情况 其中里面的weight就是CRUSH算法要使用的weight,越大代表之后PG选择该osd的概率就越大 ceph -s //查看整体ceph情况 health_ok才是正常的 ceph osd out osd.1 //将osd.1踢出集群 ceph osd i…...
注销网站备案时间/发布软文是什么意思
VMware 中 Ubuntu的安装 步骤 1.文件>新建虚拟机 2.下一步 3.下一步 4.稍后安装操作系统 5.下一步 6.自己取创建的虚拟机名字和存放路径 7.根据自己电脑的配置选择配置 8.选择虚拟机的内存,一般为2G 9.默认下一步 10.下一步 11.下一步 12.选择创建新虚拟磁盘 1…...
甘孜州住房城乡建设局网站/2023b站免费推广入口
“private是私有的,其他类是不能访问的,子类也不可以访问,所以你可以重新实现父类的该方法,不会有冲突,但是你重新实现的方法,不叫重写也不叫重载,是一个该子类新增的方法,和子类的一般扩展方法一样” public class A {private void print() {System.out.println("A"…...
做公益网站怎么赚钱/推广普通话文字内容
一、DNS:域名系统。 主要用来记录(登记)域名和IP地址的映射关系(对应关系)。 功能:域名解析。 正向解析:根据域名来解析出IP地址。域名----->IP 反向解析:根据IP地址来解析出域名。IP----->域名 ---------------------…...
网站建设公司如何拓宽业务/seo关键词排名公司
作者:UncleChen来源:http://unclechen.github.io/最近在工作中遇到写一些API,这些API的请求参数非常多,嵌套也非常复杂,如果参数的校验代码全部都手动去实现,写起来真的非常痛苦。正好Spring轮子里面有一个…...
2023年免费进入b站/精准客户数据采集软件
学习web编程的方法:1、学习html和css;2、学习javascript;3、了解web服务器;4、学习一门服务器端脚本语言;5、学习数据库及SQL语法;6、学习web框架。如何学习web开发,需要掌握哪些方面࿱…...
网站建设好推荐/推广类软文
最全的cmap的用法 此文是复制来的0.0 1. map最基本的构造函数;map<string ,int>mapstring; map<int,string >mapint;map<sring,char>mapstring; map< char ,string>mapchar;map<char,int>mapchar; map<int ,char>mapint&#x…...