3步打造C# API安全密盾

news2025/2/7 21:23:30

引言:API 安全的重要性

在数字化浪潮中,应用程序编程接口(API)已成为不同软件系统之间通信和数据交互的关键桥梁。无论是企业内部的微服务架构,还是面向外部用户的在线服务,API 都承担着数据传输和业务逻辑执行的重任。据相关数据显示,如今大部分互联网流量(71%)都是 API 调用 ,这充分凸显了 API 在现代互联网架构中的核心地位。

但随着 API 的广泛应用,其安全问题也日益凸显。API 作为访问敏感数据的直接途径,一旦遭受攻击,后果不堪设想。数据泄露可能导致用户个人信息、商业机密等重要数据被窃取,给企业和用户带来巨大的损失;身份验证失败可能让攻击者绕过权限控制,非法访问受限资源;中间人攻击则可能篡改传输数据,破坏数据的完整性和真实性;注入攻击、DDoS 攻击等也会对系统的稳定性和可用性造成严重威胁。根据 Fastly 的一项调查,95% 的企业在过去 1 年中遇到过 API 安全问题 ,而 Marsh McLennan 的研究表明,与 API 相关的安全事件每年给全球企业造成的损失高达 750 亿美元 。这些惊人的数据警示着我们,API 安全已成为保障数据安全和业务流程正常运行的关键环节。

C# 作为一种强大的编程语言,在构建安全可靠的 API 方面具有显著优势。它依托于丰富的.NET 框架,为开发者提供了一套全面且易用的加密和安全相关的类库,如 System.Security.Cryptography 命名空间,涵盖了从对称加密、非对称加密到哈希函数等多种常用的安全机制,能够满足不同场景下的安全需求。接下来,我们就深入探讨如何利用 C# 的这些特性,分三步打造坚不可摧的 API 安全密盾。

第一步:加密前的密谋 —— 了解基础

(一)加密概念介绍

在深入探讨如何使用 C# 构建 API 安全防护体系之前,我们需要先熟悉几种常见的加密概念及其特性,它们是构建安全密盾的基石。

对称加密,就像一把钥匙开一把锁,加密和解密过程使用的是同一个密钥。这种加密方式的显著优势在于加密和解密的速度极快,能够高效地处理大量数据。例如,在一些对数据处理速度要求较高的场景中,如实时数据传输、大规模数据存储加密等,对称加密能够迅速完成加密和解密操作,确保数据的快速流转。但它也存在一个明显的短板,那就是密钥的管理难度较大。由于加密和解密使用相同的密钥,在数据传输之前,发送方和接收方必须通过安全的方式商定并妥善保存这个密钥。一旦密钥在传输过程中被窃取,整个加密体系就会面临被攻破的风险 。常见的对称加密算法有 AES(Advanced Encryption Standard)、DES(Data Encryption Standard)等,其中 AES 以其出色的安全性和性能,成为了目前应用最为广泛的对称加密算法之一 。

非对称加密则引入了一对密钥:公钥和私钥。公钥可以公开分发,任何人都可以使用它来加密消息;而私钥则由持有者妥善保管,只有私钥的拥有者才能用它来解密使用对应公钥加密的消息。这种加密方式的安全性极高,因为从公钥几乎无法推断出私钥,即使攻击者获取了公钥和密文,也难以破解出原始数据。它常用于数字签名、身份验证等场景,比如在电子合同签署过程中,使用非对称加密可以确保签名的不可伪造性和消息的完整性。然而,非对称加密的加密和解密过程涉及复杂的数学运算,速度相对较慢,在处理大量数据时效率较低 。典型的非对称加密算法有 RSA(Rivest-Shamir-Adleman)、ECC(Elliptic Curve Cryptography)等 。

哈希(Hash)是一种单向的摘要算法,它能将任意长度的输入数据转换为固定长度的哈希值。哈希的主要特点是不可逆性,即无法从哈希值反向推导出原始数据。它常用于验证数据的完整性,比如在文件传输过程中,发送方计算文件的哈希值并一同发送,接收方在收到文件后重新计算哈希值,若两者一致,则说明文件在传输过程中未被篡改。但哈希并不适合直接用于加密通信,因为它无法提供保密性,任何人都可以计算出相同数据的哈希值 。常见的哈希算法有 SHA-256(Secure Hash Algorithm 256-bit)、MD5(Message-Digest Algorithm 5)等,不过由于 MD5 存在碰撞风险,安全性逐渐受到质疑,在安全要求较高的场景中已逐渐被 SHA-256 等更安全的算法所取代 。

(二)混合加密策略原理

在 API 加密的实际应用中,单一的加密方式往往难以满足复杂的安全需求,因此我们通常采用混合加密策略,将对称加密和非对称加密的优势结合起来。

具体来说,对称加密用于保护数据主体,因为它的加密速度快,能够高效地处理大量的数据传输,确保 API 的性能不受太大影响。例如,在 API 请求和响应中,对包含敏感信息的主体数据进行对称加密,使得即使数据在传输过程中被截获,攻击者也难以直接获取其中的内容。

而非对称加密则用于保护对称加密所使用的密钥。由于对称加密的密钥管理是一个难题,通过非对称加密,我们可以使用接收方的公钥对对称加密的密钥进行加密传输。这样,只有拥有对应私钥的接收方才能解密得到对称密钥,从而保证了对称密钥在传输过程中的安全性。

以一个简单的 API 数据传输场景为例,客户端生成一个随机的对称密钥,使用该密钥对要发送给服务器的数据进行对称加密,得到密文数据。然后,客户端使用服务器的公钥对这个对称密钥进行非对称加密,得到加密后的密钥。在传输时,将密文数据和加密后的密钥一同发送给服务器。服务器收到后,首先使用自己的私钥解密得到对称密钥,再用这个对称密钥解密密文数据,从而获取到原始的明文数据。

这种混合加密策略既利用了对称加密的高效性,又借助了非对称加密的高安全性,实现了安全与性能的平衡,是保障 API 数据安全传输的常用且有效的手段 。

第二步:C# 加密实战 —— 走起!

(一)准备阶段:引入帮手

在 C# 项目中,我们首先要引入加密相关的命名空间,这些命名空间就像是我们打造安全密盾的得力工具。主要涉及System.Security.Cryptography和System.Text。System.Security.Cryptography命名空间是加密的核心库,它提供了丰富的加密算法和工具类,涵盖了对称加密、非对称加密、哈希算法等各种加密机制,是实现数据加密和解密的关键所在 。而System.Text命名空间则用于字符串处理,在加密过程中,我们经常需要将字符串转换为字节数组进行处理,或者将加密后的字节数组再转换回字符串形式,System.Text命名空间中的类和方法为这些操作提供了便利 。

引入这两个命名空间的代码如下:

using System.Security.Cryptography; // 加密核心库
using System.Text; // 字符串处理

通过引入这两个命名空间,我们的项目就具备了使用各种加密算法和进行字符串处理的能力,为后续的加密实战奠定了基础。

(二)对称加密:AES 的秘密

在了解了加密的基本概念和准备好必要的工具后,我们开始使用 AES 进行对称加密的实战。AES(Advanced Encryption Standard)是一种被广泛应用的对称加密算法,以其安全性高、速度快等优点,成为了保护数据主体的首选算法之一 。

  1. 代码实现

以下是使用 AES 进行对称加密的 C# 代码:

public static byte[] EncryptStringToBytes_Aes(string plainText, byte[] key, byte[] iv)
{
    using (Aes aesAlg = Aes.Create())
    {
        aesAlg.Key = key;
        aesAlg.IV = iv;
        ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
        using (MemoryStream msEncrypt = new MemoryStream())
        {
            using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
            {
                using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                {
                    swEncrypt.Write(plainText);
                }
                return msEncrypt.ToArray();
            }
        }
    }
}
  1. 原理注释

这段代码就像是一场精心编排的加密魔术,将明文字符串plainText加密成字节数组返回。具体步骤如下:

  • 首先,通过Aes.Create()创建一个 AES 加密算法的实例aesAlg 。这个实例是我们进行加密操作的核心工具,它提供了一系列的属性和方法来配置和执行加密过程 。

  • 然后,设置aesAlg的Key和IV属性。Key是加密和解密使用的密钥,必须妥善保管,因为一旦密钥泄露,加密的数据就可能被轻易破解 。IV(Initialization Vector,初始化向量)是一个随机值,用于增加加密的安全性,它和密钥一起确保相同的明文在不同的加密操作中生成不同的密文,防止攻击者通过分析密文来破解加密算法 。

  • 接着,调用aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV)创建一个加密器encryptor 。这个加密器负责执行实际的加密操作,它根据设置的密钥和初始化向量,将明文数据按照 AES 算法的规则进行加密变换 。

  • 之后,创建一个MemoryStream对象msEncrypt,它用于在内存中存储加密后的字节数据 。同时,创建一个CryptoStream对象csEncrypt,并将其与msEncrypt和encryptor关联起来 。CryptoStream就像是一个桥梁,它将加密器和内存流连接起来,使得加密后的字节数据能够正确地写入到内存流中 。

  • 再创建一个StreamWriter对象swEncrypt,它用于将明文字符串写入到CryptoStream中 。在写入过程中,CryptoStream会自动调用加密器对写入的数据进行加密,并将加密后的字节数据存储到MemoryStream中 。

  • 最后,通过msEncrypt.ToArray()将MemoryStream中的加密字节数据转换为字节数组并返回 。这个字节数组就是加密后的密文,它可以被安全地传输或存储 。

在实际应用中,务必妥善保管好密钥key和初始化向量iv,可以将它们存储在安全的配置文件中,或者使用硬件安全模块(HSM)等设备来存储和管理,以确保加密的安全性 。

(三)非对称加密:RSA 的守护

虽然 AES 对称加密可以高效地保护数据主体,但密钥的传输安全是一个关键问题。为了解决这个问题,我们使用 RSA 非对称加密来保护 AES 密钥的传输。RSA(Rivest-Shamir-Adleman)是一种经典的非对称加密算法,它基于大整数分解的数学难题,提供了极高的安全性 。

  1. 代码实现

以下是用 RSA 加密 AES 密钥的 C# 代码:

public static byte[] EncryptUsingRSA(byte[] dataToEncrypt, RSAParameters publicKey)
{
    using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
    {
        rsa.ImportParameters(publicKey);
        return rsa.Encrypt(dataToEncrypt, false); // false 表示使用公钥加密
    }
}
  1. 原理注释

这段代码的作用是使用 RSA 的公钥对需要加密的数据dataToEncrypt(通常是 AES 密钥)进行加密 。具体实现步骤如下:

  • 首先,创建一个RSACryptoServiceProvider对象rsa,它是 RSA 加密算法在 C# 中的实现类,提供了一系列用于 RSA 加密、解密、签名和验证的方法 。

  • 然后,通过rsa.ImportParameters(publicKey)导入 RSA 的公钥参数publicKey 。公钥参数包含了用于加密的关键信息,通过导入公钥参数,rsa对象就可以使用这个公钥进行加密操作 。

  • 最后,调用rsa.Encrypt(dataToEncrypt, false)方法对数据dataToEncrypt进行加密 。其中,第二个参数false表示使用公钥进行加密 。加密后的字节数组将被返回,这个加密后的字节数组就是经过 RSA 公钥加密后的 AES 密钥,只有拥有对应私钥的接收方才能解密得到原始的 AES 密钥 。

在这个过程中,RSA 就像一位忠诚的骑士,手持公钥之剑,守护着我们的 AES 密钥安全过河(在网络中传输) 。公钥可以公开分发,任何人都可以使用它来加密数据,但只有持有对应私钥的接收方才能解密 。因此,私钥的安全性至关重要,必须严格保密,防止私钥泄露导致加密数据被破解 。

第三步:实战演练 —— 整合加密步骤

(一)生成 RSA 密钥对

在实际应用中,首先需要生成 RSA 密钥对,这是实现非对称加密的基础。在 C# 中,使用RSA.Create()方法可以轻松生成 RSA 密钥对,其中包含公钥和私钥 。公钥用于加密数据,私钥用于解密数据,两者相互关联且缺一不可 。以下是生成 RSA 密钥对的代码示例:

using (RSA rsa = RSA.Create())
{
    // 导出公钥参数
    RSAParameters publicKey = rsa.ExportParameters(false);
    // 导出私钥参数
    RSAParameters privateKey = rsa.ExportParameters(true);
    // 这里可以将公钥和私钥保存到安全的地方,例如配置文件或密钥管理系统
    // 为了演示方便,我们直接打印公钥和私钥的字节数组
    Console.WriteLine("公钥: " + BitConverter.ToString(publicKey.Exponent).Replace("-", "") + BitConverter.ToString(publicKey.Modulus).Replace("-", ""));
    Console.WriteLine("私钥: " + BitConverter.ToString(privateKey.D).Replace("-", "") + BitConverter.ToString(privateKey.Modulus).Replace("-", ""));
}

在这段代码中,RSA.Create()创建了一个RSA对象实例,它是 RSA 加密算法的具体实现 。通过rsa.ExportParameters(false)方法导出公钥参数,其中false表示不包含私钥信息 ;通过rsa.ExportParameters(true)方法导出私钥参数,true表示包含私钥信息 。在实际应用中,私钥必须严格保密,建议将其存储在安全的硬件设备(如硬件安全模块 HSM)或经过加密的存储介质中 ,以防止私钥泄露导致加密体系被攻破 。

(二)使用 AES 加密数据

选择一段明文数据,然后利用前面实现的 AES 加密方法对其进行加密 。假设我们有一段表示用户敏感信息的字符串,需要将其加密后传输 。以下是使用 AES 加密数据的示例代码:

// 假设这是我们要加密的明文数据
string plainText = "用户的敏感信息,如身份证号、银行卡号等";
// 生成AES加密所需的密钥和初始化向量
byte[] key = new byte[32]; // 32字节的密钥,适用于AES-256
byte[] iv = new byte[16]; // 16字节的初始化向量
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
{
    rng.GetBytes(key);
    rng.GetBytes(iv);
}
// 调用AES加密方法
byte[] encryptedBytes = EncryptStringToBytes_Aes(plainText, key, iv);
// 将加密后的字节数组转换为Base64字符串,以便于传输或存储
string encryptedText = Convert.ToBase64String(encryptedBytes);
Console.WriteLine("加密后的密文: " + encryptedText);

在这段代码中,首先定义了要加密的明文字符串plainText 。然后通过RNGCryptoServiceProvider生成随机的 AES 密钥key和初始化向量iv ,确保每次加密使用的密钥和向量都是不同的,增加加密的安全性 。接着调用之前实现的EncryptStringToBytes_Aes方法对明文进行加密,得到加密后的字节数组encryptedBytes 。最后,为了便于传输和存储,将加密后的字节数组转换为 Base64 编码的字符串encryptedText 。

(三)用 RSA 加密 AES 密钥

为了保证 AES 密钥在传输过程中的安全,我们使用 RSA 的公钥对 AES 密钥进行加密 。假设已经生成了 RSA 密钥对,并且获取到了公钥参数 。以下是用 RSA 加密 AES 密钥的代码:

// 假设已经生成了RSA密钥对,并获取到公钥参数
RSAParameters publicKey = GetPublicKey(); // 假设这是获取公钥的方法
// 使用RSA加密AES密钥
byte[] encryptedAesKey = EncryptUsingRSA(key, publicKey);
// 将加密后的AES密钥转换为Base64字符串,以便于传输
string encryptedAesKeyText = Convert.ToBase64String(encryptedAesKey);
Console.WriteLine("加密后的AES密钥: " + encryptedAesKeyText);

在这段代码中,首先通过GetPublicKey()方法获取 RSA 公钥参数(这里假设已经有一个方法来获取公钥) 。然后调用EncryptUsingRSA方法,使用 RSA 公钥对 AES 密钥key进行加密,得到加密后的 AES 密钥字节数组encryptedAesKey 。最后,同样将加密后的 AES 密钥转换为 Base64 编码的字符串encryptedAesKeyText ,方便在网络中传输 。

(四)发送加密后的数据

在完成数据的加密和 AES 密钥的加密后,我们将加密后的数据和加密后的 AES 密钥一起发送给接收方 。接收方在收到数据后,需要按照相反的步骤进行解密 。

  1. 发送方操作

将 AES 加密后的密文encryptedText和 RSA 加密后的 AES 密钥encryptedAesKeyText一起发送给接收方 。可以通过网络请求(如 HTTP 请求)将这些数据发送到目标服务器 。例如,使用HttpClient发送 POST 请求:

using (HttpClient client = new HttpClient())
{
    var content = new MultipartFormDataContent();
    content.Add(new StringContent(encryptedText), "encryptedData");
    content.Add(new StringContent(encryptedAesKeyText), "encryptedAesKey");
    HttpResponseMessage response = client.PostAsync("https://example.com/api/receive", content).Result;
    if (response.IsSuccessStatusCode)
    {
        Console.WriteLine("数据发送成功");
    }
    else
    {
        Console.WriteLine("数据发送失败: " + response.StatusCode);
    }
}

在这段代码中,创建了一个HttpClient对象用于发送 HTTP 请求 。使用MultipartFormDataContent将加密后的密文和加密后的 AES 密钥作为表单数据添加到请求中 ,分别命名为encryptedData和encryptedAesKey 。然后通过client.PostAsync方法发送 POST 请求到指定的 API 地址https://example.com/api/receive ,并根据响应状态码判断数据是否发送成功 。

  1. 接收方操作

接收方在收到请求后,首先使用自己的 RSA 私钥解密得到 AES 密钥 ,然后再用 AES 密钥解密密文数据 。以下是接收方的解密代码示例:

// 假设已经获取到RSA私钥参数
RSAParameters privateKey = GetPrivateKey(); // 假设这是获取私钥的方法
// 从请求中获取加密后的AES密钥和密文数据
string receivedEncryptedAesKey = Request.Form["encryptedAesKey"];
string receivedEncryptedText = Request.Form["encryptedData"];
// 将Base64编码的字符串转换回字节数组
byte[] receivedEncryptedAesKeyBytes = Convert.FromBase64String(receivedEncryptedAesKey);
byte[] receivedEncryptedTextBytes = Convert.FromBase64String(receivedEncryptedText);
// 使用RSA私钥解密AES密钥
byte[] decryptedAesKey = DecryptUsingRSA(receivedEncryptedAesKeyBytes, privateKey);
// 使用AES密钥解密密文数据
string decryptedText = DecryptStringFromBytes_Aes(receivedEncryptedTextBytes, decryptedAesKey, GetIV()); // 假设这是获取IV的方法
Console.WriteLine("解密后的明文: " + decryptedText);

在这段代码中,首先通过GetPrivateKey()方法获取 RSA 私钥参数(假设已经有获取私钥的方法) 。然后从 HTTP 请求的表单数据中获取加密后的 AES 密钥receivedEncryptedAesKey和密文数据receivedEncryptedText 。将这两个 Base64 编码的字符串转换回字节数组 。接着调用DecryptUsingRSA方法(假设已经实现该方法用于 RSA 解密),使用 RSA 私钥对加密后的 AES 密钥进行解密,得到原始的 AES 密钥decryptedAesKey 。最后,调用DecryptStringFromBytes_Aes方法(假设已经实现该方法用于 AES 解密),使用解密得到的 AES 密钥和获取到的初始化向量(这里假设通过GetIV()方法获取)解密密文数据,得到原始的明文decryptedText 。通过这样的流程,实现了数据的安全传输和解密 。

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

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

相关文章

vscode 如何通过Continue引入AI 助手deepseek

第一步: 在deepseek 官网上注册账号,得到APIKeys(deepseek官网地址) 创建属于自己的APIKey,然后复制这个key,(注意保存自己的key)! 第二步: 打开vscode,在插件市场安装Continue插件, 点击设置,添加deepseek模型,默认…

通过docker安装部署deepseek以及python实现

前提条件 Docker 安装:确保你的系统已经安装并正确配置了 Docker。可以通过运行 docker --version 来验证 Docker 是否安装成功。 网络环境:保证设备有稳定的网络连接,以便拉取 Docker 镜像和模型文件。 步骤一:拉取 Ollama Docker 镜像 Ollama 可以帮助我们更方便地管理…

iOS 音频录制、播放与格式转换

iOS 音频录制、播放与格式转换:基于 AVFoundation 和 FFmpegKit 的实现 在 iOS 开发中,音频处理是一个非常常见的需求,比如录音、播放音频、音频格式转换等。本文将详细解读一段基于 AVFoundation 和 FFmpegKit 的代码,展示如何实现音频录制、播放以及 PCM 和 AAC 格式之间…

RK3576——USB3.2 OTG无法识别到USB设备

问题:使用硬盘接入到OTG接口无热插拔信息,接入DP显示屏无法正常识别到显示设备,但是能通过RKDdevTool工具烧录系统。 问题分析:由于热插拔功能实现是靠HUSB311芯片完成的,因此需要先确保HUSB311芯片驱动正常工作。 1. …

【MySQL】语言连接

语言连接 一、下载二、mysql_get_client_info1、函数2、介绍3、示例 三、其他函数1、mysql_init2、mysql_real_connect3、mysql_query4、mysql_store_result5、mysql_free_result6、mysql_num_fields7、mysql_num_rows8、mysql_fetch_fields9、mysql_fetch_row10、mysql_close …

20240206 adb 连不上手机解决办法

Step 1: lsusb 确认电脑 usb 端口能识别设备 lsusb不知道设备有没有连上,就插拔一下,对比观察多了/少了哪个设备。 Step 2: 重启 adb server sudo adb kill-serversudo adb start-serveradb devices基本上就可以了~ Reference https://b…

基于ansible部署elk集群

ansible部署 ELK部署 ELK常见架构 (1)ElasticsearchLogstashKibana:这种架构是最常见的一种,也是最简单的一种架构,这种架构通过Logstash收集日志,运用Elasticsearch分析日志,最后通过Kibana中…

Mac上搭建k8s环境——Minikube

1、在mac上安装Minikube可执行程序 brew cask install minikub 安装后使用minikube version命令查看版本 2、安装docker环境 brew install --cask --appdir/Applications docker #安装docker open -a Docker #启动docker 3、安装kubectl curl -LO https://storage.g…

MTGNN论文解读

模型架构 MTGNN 由多个模块组合而成,目标是捕捉多变量时间序列中的空间(变量间)和时间(时序)依赖。 图学习层:用于自适应地学习图的邻接矩阵,发现变量之间的关系。图卷积模块:根据邻…

C语言:函数栈帧的创建和销毁

目录 1.什么是函数栈帧2.理解函数栈帧能解决什么问题3.函数栈帧的创建和销毁的过程解析3.1 什么是栈3.2 认识相关寄存器和汇编指令3.3 解析函数栈帧的创建和销毁过程3.3.1 准备环境3.3.2 函数的调用堆栈3.3.3 转到反汇编3.3.4 函数栈帧的创建和销毁 1.什么是函数栈帧 在写C语言…

VSCode便捷开发

一、常用插件 Vue 3 Snippets、Vetur、Vue - Official 二、常用开发者工具 三、Vue中使用Element-UI 安装步骤: 1、在VSCode的终端执行如下指令: npm i element-ui -S 2、在main.js中全局引入: import Vue from vue; import ElementUI from …

二、tsp学习笔记——LINUX SDK编译

开发环境:window11 wsl ubuntu24.04 lypwslDESKTOP-39T8VTC:~$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 24.04.1 LTS Release: 24.04 Codename: noble linux_sdk同步 tspi_linux_sdk_repo_202…

分析用户请求K8S里ingress-nginx提供的ingress流量路径

前言 本文是个人的小小见解,欢迎大佬指出我文章的问题,一起讨论进步~ 我个人的疑问点 进入的流量是如何自动判断进入iptables的四表?k8s nodeport模式的原理? 一 本机环境介绍 节点名节点IPK8S版本CNI插件Master192.168.44.1…

初阶数据结构:树---堆

目录 一、树的概念 二、树的构成 (一)、树的基本组成成分 (二)、树的实现方法 三、树的特殊结构------二叉树 (一)、二叉树的概念 (二)、二叉树的性质 (三&#…

feign 远程调用详解

在平常的开发工作中,我们经常需要跟其他系统交互,比如调用用户系统的用户信息接口、调用支付系统的支付接口等。那么,我们应该通过什么方式进行系统之间的交互呢?今天,简单来总结下 feign 的用法。 1:引入依…

Sentinel的安装和做限流的使用

一、安装 Release v1.8.3 alibaba/Sentinel GitHubA powerful flow control component enabling reliability, resilience and monitoring for microservices. (面向云原生微服务的高可用流控防护组件) - Release v1.8.3 alibaba/Sentinelhttps://github.com/alibaba/Senti…

讯飞智作 AI 配音技术浅析(三):自然语言处理

自然语言处理(NLP)是讯飞智作 AI 配音技术的重要组成部分,负责将输入的文本转换为机器可理解的格式,并提取出文本的语义和情感信息,以便生成自然、富有表现力的语音。 一、基本原理 讯飞智作 AI 配音的 NLP 技术主要包…

wxWidgets生成HTML文件,带图片转base64数据

编译环境大家可以看我之前的文章,CodeBlocks + msys2 + wx3.2,win10 这里功能就是生成HTML文件,没用HTML库,因为是自己固定的格式,图片是一个vector,可以动态改变数量的。 效果如下: #include <wx/string.h> #include <wx/file.h> #include <wx/ima…

【matlab基本使用笔记】

ctrl a i 代码格式化 fzero求非线性函数的根 arrayfun将函数应用于每个数组元素 format long长格式输出 format long g取消科学计数法 linspace logspace 一、界面使用 1.创建matlab脚本 利用.m后缀的脚本文件&#xff08;又称为m文件&#xff09;编程&#xff1a; 点击…

机器学习--python基础库之Matplotlib (1) 超级详细!!!

机器学习--python基础库Matplotlib 机器学习--python基础库Matplotlib0 介绍1 实现基础绘图-某城市温度变化图1.1绘制基本图像1.2实现一些其他功能 2 再一个坐标系中绘制多个图像3 多个坐标系显示-plt.subplots(面向对象的画图方法)4 折线图的应用场景 机器学习–python基础库M…