RSAUtil 前端 JavaScript JSEncrypt 实现 RSA (长文本)加密解密
文章归档:https://www.yuque.com/u27599042/coding_star/cl4dl599pdmtllw1
依赖
- import JSEncrypt from ‘jsencrypt’
pnpm i jsencrypt
- import {stringIsNull} from “@/utils/string_utils.js”:https://www.yuque.com/u27599042/coding_star/slncupw7un3ce7cb
- import {isNumber} from “@/utils/number_utils.js”:https://www.yuque.com/u27599042/coding_star/tuwmm3ghf5lgo4bw
导入依赖
import JSEncrypt from 'jsencrypt'
import {stringIsNull} from "@/utils/string_utils.js"
import {isNumber} from "@/utils/number_utils.js"
内部变量
/*** RSA 加密算法获取密钥对中的公钥使用的 key** @type {string}*/
export const PUBLIC_KEY = 'RSAPublicKey'/*** RSA 加密算法获取密钥对中的密钥使用的 key** @type {string}*/
export const PRIVATE_KEY = 'RSAPrivateKey'/*** RSA 密钥对的 bit 数(密钥对的长度)。* 常用 1024、2048,密钥对的 bit 数,越大越安全,但是越大对服务器的消耗越大** @type {number}*/
let keySize = 1024/*** keySize bit 数下的 RSA 密钥对所能够加密的最大明文大小。* RSA 算法一次能加密的明文长度与密钥长度(RSA 密钥对的 bit 数)成正比,* 默认情况下,Padding 方式为 OPENSSL_PKCS1_PADDING,RSA 算法会使* 用 11 字节的长度用于填充,所以默认情况下,RSA 所能够加密的最大明文大* 小为 (keySize / 8 - 11) byte** @type {number}*/
let maxEncryptPlainTextLen = 117/*** keySize bit 数下的 RSA 密钥对所能够解密的最大密文大小。* (keySize / 8) byte** @type {number}*/
let maxDecryptCipherTextLen = 128/*** 密钥长度为 1024 bit 下,通过公钥生成的密文字符串的长度** @type {number}*/
let cipherTextStrLen = 172
设置 RSA 密钥对的 bit 数
/*** 为 RSA 密钥对的 bit 数赋值,同时重新计算 keySize bit 数下的* RSA 密钥对所能够加密的最大明文大小、所能够解密的最大密文大小** @param size RSA 密钥对的 bit 数*/
export function setKeySize(size) {if (!isNumber(size) || size <= 0) {throw new TypeError("参数 {size} 需要是大于 0 的整数")}keySize = sizemaxEncryptPlainTextLen = keySize / 8 - 11maxDecryptCipherTextLen = keySize / 8
}
获取指定字符的 UTF8 字节大小
/*** 获取指定字符的 UTF8 字节大小* 代码来源: https://blog.csdn.net/csdn_yuan_/article/details/107428744** @param charCode 字符编码* @return {number} 指定字符的 UTF8 字节大小*/
export function getCharByteSizeUTF8(charCode) {if (!isNumber(charCode) || charCode < 0) {throw new TypeError("参数 {charCode} 需要是大于 0 的整数")}//字符代码在000000 – 00007F之间的,用一个字节编码if (charCode <= 0x007f) {return 1}//000080 – 0007FF之间的字符用两个字节else if (charCode <= 0x07ff) {return 2}//000800 – 00D7FF 和 00E000 – 00FFFF之间的用三个字节,注: Unicode在范围 D800-DFFF 中不存在任何字符else if (charCode <= 0xffff) {return 3}//010000 – 10FFFF之间的用4个字节else {return 4}
}
获取字符串的 UTF8 字节长度
/*** 获取字符串的 UTF8 字节长度* 代码来源: https://blog.csdn.net/csdn_yuan_/article/details/107428744** @param str 字符串* @returns {number} 字符串的 UTF8 字节长度*/
export function getStrByteLenUTF8(str) {if (stringIsNull(str)) {throw new TypeError("参数 {str} 需要非空字符串")}// 获取字符串的字符长度const strLen = str.length// 保存字符串的字节长度let strByteLen = 0// 遍历判断字符串中的每个字符,统计字符串的 UTF8 字节长度for (let i = 0; i < strLen; i++) {// 获取当前遍历字符的编码let charCode = str.charCodeAt(i);// 获取并记录当前遍历字符的 UTF8 字节大小strByteLen += getCharByteSizeUTF8(charCode)}return strByteLen
}
获取字符串的 UTF8 字节长度, 同时获取按照指定的子字符串字节长度划分的子字符串数组
/*** 获取字符串的 UTF8 字节长度,同时获取按照指定的子字符串字节长度划分的子字符串数组* 代码参考: https://blog.csdn.net/csdn_yuan_/article/details/107428744** @param str 字符串* @param subStrByteLen 子字符串字节长度* @return {[]} 按照指定的子字符串字节长度划分的子字符串数组*/
export function getStrByteLenUTF8AndSubStrs(str, subStrByteLen) {if (stringIsNull(str)) {throw new TypeError("参数 {str} 需要非空字符串")}if (!isNumber(subStrByteLen) || subStrByteLen <= 0) {throw new TypeError("参数 {subStrByteLen} 需要是大于 0 的整数")}// 获取字符串的字符长度const strLen = str.length// 保存字符串的字节长度let strByteLen = 0// 记录上一次分隔的字符串的位置let preIdx = 0;// 记录当前子字符串的字节大小let subStrByteSize = 0;// 记录子字符串const subStrs = []// 遍历判断字符串中的每个字符,统计字符串的 UTF8 字节长度for (let i = 0; i < strLen; i++) {// 获取当前遍历字符的编码let charCode = str.charCodeAt(i);// 获取并记录当前遍历字符的 UTF8 字节大小let charByteSizeUTF8 = getCharByteSizeUTF8(charCode)strByteLen += charByteSizeUTF8// 当前子字符串的字节大小subStrByteSize += charByteSizeUTF8// 子字符串达到切割长度if (subStrByteSize > subStrByteLen) {// 当前子字符串加入返回结果数组中subStrs.push(str.substring(preIdx, i))// 更新数据preIdx = isubStrByteSize = charByteSizeUTF8}}// 如果还有子字符串还为加入返回结果数组中if (subStrByteSize > 0) {subStrs.push(str.substring(preIdx))}return {strByteLen,subStrs}
}
使用公钥对明文进行加密(支持长文本)
/*** 使用公钥对明文进行加密(支持长文本)** @param publicKey 公钥* @param plainText 明文* @returns {string} 明文加密后的密文*/
export function encryptByPublicKey(publicKey, plainText) {if (stringIsNull(publicKey) || stringIsNull(plainText)) {throw new TypeError("参数 {publicKey} {plainText} 需要非空字符串")}// 获取明文字符串的字节大小和根据指定字节大小划分的子字符串数组const { strByteLen: plainTextByteSize, subStrs: plainTextSubStrArr } = getStrByteLenUTF8AndSubStrs(plainText,maxEncryptPlainTextLen)// 明文加密后的完整密文let cipherText = ""// 对明文进行分段加密plainTextSubStrArr.forEach(subStr => {// 获取加密解密器const encryptor = new JSEncrypt()// 设置公钥encryptor.setPublicKey(publicKey)// 加密cipherText += encryptor.encrypt(subStr)})return cipherText
}
使用私钥对密文进行解密(支持长文本)
注意: 此方法只适用于使用和上述加密方法逻辑相同的加密处理得到的密文的解密
/*** 使用私钥对密文进行解密(支持长文本)* 注意: 此方法只适用于使用和上述加密方法逻辑相同的加密处理得到的密文的解密** @param privateKey 密钥* @param cipherText 密文* @return {string} 密文解密后的明文*/
export function decryptByPrivateKey(privateKey, cipherText) {if (stringIsNull(privateKey) || stringIsNull(cipherText)) {throw new TypeError("参数 {privateKey} {cipherText} 需要非空字符串")}// 获取密文的字符长度let cipherTextLen = cipherText.length// 计算分段解密的次数, cipherTextStrLen 每段密文长度let decryptCount = cipherTextLen / cipherTextStrLen// 解密后的完整明文let plainText = ""// 对密文进行分段解密for (let i = 0; i < decryptCount; i++) {// 分段密文距离开始位置的偏移量let offSet = i * cipherTextStrLenlet subCipherText = cipherText.substring(offSet, offSet + cipherTextLen)// 加密解密器const encryptor = new JSEncrypt()// 设置私钥encryptor.setPrivateKey(privateKey)// 解密plainText += encryptor.decrypt(subCipherText)}return plainText
}
与 RSAUtil 搭配的 Java 后端 RSAUtilInteractiveWithFrontEnd
完整源码
import JSEncrypt from 'jsencrypt'
import {stringIsNull} from "@/utils/string_utils.js"
import {isNumber} from "@/utils/number_utils.js"/*** RSA 加密算法获取密钥对中的公钥使用的 key** @type {string}*/
export const PUBLIC_KEY = 'RSAPublicKey'/*** RSA 加密算法获取密钥对中的密钥使用的 key** @type {string}*/
export const PRIVATE_KEY = 'RSAPrivateKey'/*** RSA 密钥对的 bit 数(密钥对的长度)。* 常用 1024、2048,密钥对的 bit 数,越大越安全,但是越大对服务器的消耗越大** @type {number}*/
let keySize = 1024/*** keySize bit 数下的 RSA 密钥对所能够加密的最大明文大小。* RSA 算法一次能加密的明文长度与密钥长度(RSA 密钥对的 bit 数)成正比,* 默认情况下,Padding 方式为 OPENSSL_PKCS1_PADDING,RSA 算法会使* 用 11 字节的长度用于填充,所以默认情况下,RSA 所能够加密的最大明文大* 小为 (keySize / 8 - 11) byte** @type {number}*/
let maxEncryptPlainTextLen = 117/*** keySize bit 数下的 RSA 密钥对所能够解密的最大密文大小。* (keySize / 8) byte** @type {number}*/
let maxDecryptCipherTextLen = 128/*** 密钥长度为 1024 bit 下,通过公钥生成的密文字符串的长度** @type {number}*/
let cipherTextStrLen = 172/*** 为 RSA 密钥对的 bit 数赋值,同时重新计算 keySize bit 数下的* RSA 密钥对所能够加密的最大明文大小、所能够解密的最大密文大小** @param size RSA 密钥对的 bit 数*/
export function setKeySize(size) {if (!isNumber(size) || size <= 0) {throw new TypeError("参数 {size} 需要是大于 0 的整数")}keySize = sizemaxEncryptPlainTextLen = keySize / 8 - 11maxDecryptCipherTextLen = keySize / 8
}/*** 获取指定字符的 UTF8 字节大小* 代码来源: https://blog.csdn.net/csdn_yuan_/article/details/107428744** @param charCode 字符编码* @return {number} 指定字符的 UTF8 字节大小*/
export function getCharByteSizeUTF8(charCode) {if (!isNumber(charCode) || charCode < 0) {throw new TypeError("参数 {charCode} 需要是大于 0 的整数")}//字符代码在000000 – 00007F之间的,用一个字节编码if (charCode <= 0x007f) {return 1}//000080 – 0007FF之间的字符用两个字节else if (charCode <= 0x07ff) {return 2}//000800 – 00D7FF 和 00E000 – 00FFFF之间的用三个字节,注: Unicode在范围 D800-DFFF 中不存在任何字符else if (charCode <= 0xffff) {return 3}//010000 – 10FFFF之间的用4个字节else {return 4}
}/*** 获取字符串的 UTF8 字节长度* 代码来源: https://blog.csdn.net/csdn_yuan_/article/details/107428744** @param str 字符串* @returns {number} 字符串的 UTF8 字节长度*/
export function getStrByteLenUTF8(str) {if (stringIsNull(str)) {throw new TypeError("参数 {str} 需要非空字符串")}// 获取字符串的字符长度const strLen = str.length// 保存字符串的字节长度let strByteLen = 0// 遍历判断字符串中的每个字符,统计字符串的 UTF8 字节长度for (let i = 0; i < strLen; i++) {// 获取当前遍历字符的编码let charCode = str.charCodeAt(i);// 获取并记录当前遍历字符的 UTF8 字节大小strByteLen += getCharByteSizeUTF8(charCode)}return strByteLen
}/*** 获取字符串的 UTF8 字节长度,同时获取按照指定的子字符串字节长度划分的子字符串数组* 代码参考: https://blog.csdn.net/csdn_yuan_/article/details/107428744** @param str 字符串* @param subStrByteLen 子字符串字节长度* @return {[]} 按照指定的子字符串字节长度划分的子字符串数组*/
export function getStrByteLenUTF8AndSubStrs(str, subStrByteLen) {if (stringIsNull(str)) {throw new TypeError("参数 {str} 需要非空字符串")}if (!isNumber(subStrByteLen) || subStrByteLen <= 0) {throw new TypeError("参数 {subStrByteLen} 需要是大于 0 的整数")}// 获取字符串的字符长度const strLen = str.length// 保存字符串的字节长度let strByteLen = 0// 记录上一次分隔的字符串的位置let preIdx = 0;// 记录当前子字符串的字节大小let subStrByteSize = 0;// 记录子字符串const subStrs = []// 遍历判断字符串中的每个字符,统计字符串的 UTF8 字节长度for (let i = 0; i < strLen; i++) {// 获取当前遍历字符的编码let charCode = str.charCodeAt(i);// 获取并记录当前遍历字符的 UTF8 字节大小let charByteSizeUTF8 = getCharByteSizeUTF8(charCode)strByteLen += charByteSizeUTF8// 当前子字符串的字节大小subStrByteSize += charByteSizeUTF8// 子字符串达到切割长度if (subStrByteSize > subStrByteLen) {// 当前子字符串加入返回结果数组中subStrs.push(str.substring(preIdx, i))// 更新数据preIdx = isubStrByteSize = charByteSizeUTF8}}// 如果还有子字符串还为加入返回结果数组中if (subStrByteSize > 0) {subStrs.push(str.substring(preIdx))}return {strByteLen,subStrs}
}/*** 使用公钥对明文进行加密(支持长文本)** @param publicKey 公钥* @param plainText 明文* @returns {string} 明文加密后的密文*/
export function encryptByPublicKey(publicKey, plainText) {if (stringIsNull(publicKey) || stringIsNull(plainText)) {throw new TypeError("参数 {publicKey} {plainText} 需要非空字符串")}// 获取明文字符串的字节大小和根据指定字节大小划分的子字符串数组const { strByteLen: plainTextByteSize, subStrs: plainTextSubStrArr } = getStrByteLenUTF8AndSubStrs(plainText,maxEncryptPlainTextLen)// 明文加密后的完整密文let cipherText = ""// 对明文进行分段加密plainTextSubStrArr.forEach(subStr => {// 获取加密解密器const encryptor = new JSEncrypt()// 设置公钥encryptor.setPublicKey(publicKey)// 加密cipherText += encryptor.encrypt(subStr)})return cipherText
}/*** 使用私钥对密文进行解密(支持长文本)* 注意: 此方法只适用于使用和上述加密方法逻辑相同的加密处理得到的密文的解密** @param privateKey 密钥* @param cipherText 密文* @return {string} 密文解密后的明文*/
export function decryptByPrivateKey(privateKey, cipherText) {if (stringIsNull(privateKey) || stringIsNull(cipherText)) {throw new TypeError("参数 {privateKey} {cipherText} 需要非空字符串")}// 获取密文的字符长度let cipherTextLen = cipherText.length// 计算分段解密的次数, cipherTextStrLen 每段密文长度let decryptCount = cipherTextLen / cipherTextStrLen// 解密后的完整明文let plainText = ""// 对密文进行分段解密for (let i = 0; i < decryptCount; i++) {// 分段密文距离开始位置的偏移量let offSet = i * cipherTextStrLenlet subCipherText = cipherText.substring(offSet, offSet + cipherTextLen)// 加密解密器const encryptor = new JSEncrypt()// 设置私钥encryptor.setPrivateKey(privateKey)// 解密plainText += encryptor.decrypt(subCipherText)}return plainText
}
相关文章:
RSAUtil 前端 JavaScript JSEncrypt 实现 RSA (长文本)加密解密
文章归档:https://www.yuque.com/u27599042/coding_star/cl4dl599pdmtllw1 依赖 import JSEncrypt from ‘jsencrypt’ pnpm i jsencryptimport {stringIsNull} from “/utils/string_utils.js”:https://www.yuque.com/u27599042/coding_star/slncupw…...
uniapp map polygons 区域填充色(fillColor)在ios显示正常,但在安卓手机显示是黑色的,怎么解决?
uniapp map polygons 区域填充色(fillColor)在ios显示正常,但在安卓手机显示是黑色的,怎么解决? <MapPage :longitude"item.centerCoord[0]" :latitude"item.centerCoord[1]":polygons"[{ points: it…...
OSCAR数据库上锁问题如何排查
关键字 oscar lock 问题描述 oscar 数据库上锁问题如何排查 解决问题思路 准备数据 create table lock_test(name varchar(10),age varchar(10));insert into lock_test values(ff,10); insert into lock_test values(yy,20); insert into lock_test values(ll,30);sessio…...
FPGA与人工智能泛谈-01
文章目录 前言一、FPGA(Field Programmable Gate Array)是什么?二、与GPU的对比1.GPU特点2. FPGA的优势三、人工智能实现的基础架构总结前言 人工智能技术的快速发展正从各个方面改变人类的生活、工作及教育等各个方面,其中人工智能算法的演进又是其中的关键一步,其中会涉及…...
【VASP】POTCAR文件
【VASP】POTCAR文件 POTCAR 文件的介绍qvasp 生成POTCARvaspkit 生成POTCAR再来认识一下各种赝势如何区分US、PAW、LDA、GGA、PW91 前言 一、4个常用的输入文件INCAR、POSCAR、POTCAR、KPOINTS INCAR: 计算任务类型是什么?怎么计算? KPOINTS: 包含了倒易…...
棒球俱乐部青少年成长体系·棒球1号位
棒球俱乐部青少年成长体系介绍 1. 培养理念 简要介绍棒球俱乐部的宗旨和培养青少年的目标 棒球俱乐部是一个致力于培养青少年棒球运动员的体育组织,其宗旨是通过提供专业的棒球训练和比赛机会,帮助青少年提高身体素质、培养团队合作精神和塑造积极向上…...
折叠式菜单怎么做编程,初学编程系统化教程初级1上线
中文编程系统化教程,不需英语基础,学习链接——入门篇课程 https://edu.csdn.net/course/detail/39036中文编程系统化教程,不需英语基础,学习链接—— 初级1课程 https://edu.csdn.net/course/detail/39061 ——————————…...
与AI对话,如何写好prompt?
玩转AIGC,优质的Prompt提示词实在是太重要了!同样的问题,换一个问法,就会得到差别迥异的答案。你是怎样和AI进行对话交流的呢?我来分享几个: 请告诉我…我想知道…对于…你有什么看法?帮我解决…...
基于YOLOv8模型和UA-DETRAC数据集的车辆目标检测系统(PyTorch+Pyside6+YOLOv8模型)
摘要:基于YOLOv8模型和UA-DETRAC数据集的车辆目标检测系统可用于日常生活中检测与定位汽车(car)、公共汽车(bus)、面包车(vans)等目标,利用深度学习算法可实现图片、视频、摄像头等方…...
0037【Edabit ★☆☆☆☆☆】【修改Bug 2】Buggy Code (Part 2)
0037【Edabit ★☆☆☆☆☆】【修改Bug 2】Buggy Code (Part 2) bugs language_fundamentals Instructions Fix the code in the code tab to pass this challenge (only syntax errors). Look at the examples below to get an idea of what the function should do. Exampl…...
【算法中的Java】— 判断语句
📒博客首页:Sonesang的博客 🎉欢迎关注🔎点赞👍收藏⭐️留言📝 ❤️ :热爱Java与算法学习,期待一起交流! 🙏作者水平很有限,如果发现错误…...
【单例模式】饿汉式,懒汉式?JAVA如何实现单例?线程安全吗?
个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ 单例设计模式 Java单例设计模式 Java单例设计模…...
Spark_SQL-DataFrame数据写出以及读写数据库(以MySQl为例)
一、数据写出 (1)SparkSQL统一API写出DataFrame数据 二、写出MySQL数据库 一、数据写出 (1)SparkSQL统一API写出DataFrame数据 统一API写法: 常见源写出: # cording:utf8from pyspark.sql import SparkSes…...
Linux进程终止
文章目录 进程退出场景进程退出码strerrorerrno浅谈进程异常exit && _exit 进程退出场景 代码运行完毕,结果正确代码运行完毕,结果不正确代码异常 进程退出码 我们写的C/C的代码,main函数每次都需要返回0,而这个return…...
0036【Edabit ★☆☆☆☆☆】【让我加油】Let‘s Fuel Up!
0036【Edabit ★☆☆☆☆☆】【让我加油 】Let’s Fuel Up! control_flow language_fundamentals numbers Instructions A vehicle needs 10 times the amount of fuel than the distance it travels. However, it must always carry a minimum of 100 fuel before setting o…...
React 中常用的几种路由跳转方式
目录 一、push跳转 1、Link组件: 二、replace跳转 三、goBack跳转(回退) 四、goForward跳转(前进) 五、 go跳转(向前或向后跳转指定步数) 一、push跳转 1、Link组件: 可以在不刷新…...
C++内存管理:其七、标准库中的allocator
首先明确一点,绝大多数情况下,是标准库中的容器使用allocator。因为容器需要频繁的申请和释放内存。 一、容器使用allocator 典型的例子: vector<int , allocator<int>> a;但是为什么我们通常的定义vector变量的方法是&#x…...
【机器学习合集】人脸表情分类任务Pytorch实现TensorBoardX的使用 ->(个人学习记录笔记)
人脸表情分类任务 注意:整个项目来自阿里云天池,下面是开发人员的联系方式,本人仅作为学习记录!!!该文章原因,学习该项目,完善注释内容,针对新版本的Pytorch进行部分代码…...
Maven - 国内 Maven 镜像仓库(加速包,冲冲冲~)
<?xml version"1.0" encoding"UTF-8" ?><!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding…...
【Solidity】智能合约案例——③版权保护合约
目录 一、合约源码分析: 二、合约整体流程: 1.部署合约: 2.添加实体: 3.查询实体 4.审核版权: 5.版权转让 一、合约源码分析: Copyright.sol:主合约,定义了版权局的实体ÿ…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
聊一聊接口测试的意义有哪些?
目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开,首…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...
【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)
LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 题目描述解题思路Java代码 题目描述 题目链接:LeetCode 3309. 连接二进制表示可形成的最大数值(中等) 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...
