RSA+AES数字信封加解密设计

article/2025/9/4 20:05:50

        登录认证、鉴权这些都做好了过后。就开始我们的加密设计了、这里采用了简化数字信封进行加密。首先客户端(浏览器)先请求一份RSA非对称密钥、如果我们采用了openresty或者有能力在nginx开发C模块的插件,就可以在这里保留一份用户的私钥,如果不行就直接在应用网关上面保存(也可以在应用网关直接读取redis获得);然后在浏览器发起请求的时候、请求体加密时本地自己生成AES密钥、在使用获得的公钥对AES密钥进行一次加密(加密结果放在请求头中),最后将请求发送到后端。后端先使用RSA的私钥解密请求头中的AES加密密钥,得到了AES明文密钥后对请求体进行解密。后端返回时,如果需要加密返回结果、也可以使用该AES密钥对结果进行加密。下图以有nginx自定义C模块或者openresty进行加解密的方式进行描述。

 

AES加密

        采用AES进行对称加密时、需要注意的是需要采用CBC模式。CBC模式会增加向量来保证加密的强度。还有为什么明明使用了RSA还需要在用AES做什么呢?为什么不全部使用RSA呢?

        首先RSA的强度是要比AES更强的、但是RSA有一个缺陷就是密文太长的话、解密的速度太慢。所以综合了两者的优点、使用RSA对AES的密钥加密,使用AES对报文体进行加密。这样既保证了密码的强度、又保证了加解密的速度问题。

AES加解密工具类

import org.apache.commons.codec.binary.Base64;import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;/*** AES 加密工具类*/
public class AESUtils {public static final String CHAR_ENCODING = "UTF-8";public static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";/*** 加密** @param data 需要加密的内容* @param key  加密密码* @return*/public static byte[] encrypt(byte[] data, byte[] key, byte[] ivKey) {if (key.length != 16) {throw new RuntimeException("Invalid AES key length (must be 16 bytes)");}try {SecretKeySpec secretKey = new SecretKeySpec(key, "AES");byte[] enCodeFormat = secretKey.getEncoded();SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, "AES");Cipher cipher = Cipher.getInstance(AES_ALGORITHM);// 创建密码器IvParameterSpec iv = new IvParameterSpec(ivKey);//使用CBC模式,需要一个向量iv,可增加加密算法的强度cipher.init(Cipher.ENCRYPT_MODE, seckey, iv);// 初始化byte[] result = cipher.doFinal(data);return result; // 加密} catch (Exception e) {e.printStackTrace();throw new RuntimeException("encrypt fail!", e);}}/*** 解密** @param data 待解密内容* @param key  解密密钥* @return*/public static byte[] decrypt(byte[] data, byte[] key,byte[] ivKey) {if (key.length != 16) {throw new RuntimeException("Invalid AES key length (must be 16 bytes)");}try {SecretKeySpec secretKey = new SecretKeySpec(key, "AES");byte[] enCodeFormat = secretKey.getEncoded();SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, "AES");// 创建密码器Cipher cipher = Cipher.getInstance(AES_ALGORITHM);// 使用CBC模式,需要一个向量iv,可增加加密算法的强度IvParameterSpec iv = new IvParameterSpec(ivKey);// 初始化cipher.init(Cipher.DECRYPT_MODE, seckey, iv);byte[] result = cipher.doFinal(data);return result; // 解密} catch (Exception e) {e.printStackTrace();throw new RuntimeException("decrypt fail!", e);}}public static String encryptToBase64(String data, String key, String iVkey) {try {byte[] valueByte = encrypt(data.getBytes(CHAR_ENCODING), key.getBytes(CHAR_ENCODING),iVkey.getBytes(CHAR_ENCODING));return new String(Base64.encodeBase64(valueByte));} catch (UnsupportedEncodingException e) {throw new RuntimeException("encrypt fail!", e);}}public static String decryptFromBase64(String data, String key, String iVkey) {try {byte[] originalData = Base64.decodeBase64(data.getBytes());final char[] chars = getChars(decrypt(originalData, key.getBytes(CHAR_ENCODING),iVkey.getBytes(CHAR_ENCODING)));StringBuffer sb = new StringBuffer();for(int i= 0 ;i < chars.length; i++){if(chars[i] == '\0'){continue;}sb.append(chars[i]);}Arrays.fill(chars,' ');return sb.toString();} catch (UnsupportedEncodingException e) {throw new RuntimeException("decrypt fail!", e);}}private static char[] getChars(byte[] bytes){Charset cs = Charset.forName(CHAR_ENCODING);ByteBuffer bb = ByteBuffer.allocate(bytes.length);bb.put(bytes);bb.flip();CharBuffer cb = cs.decode(bb);return cb.array();}public static byte[] genarateRandomKey() {KeyGenerator keygen = null;try {keygen = KeyGenerator.getInstance(AES_ALGORITHM);} catch (NoSuchAlgorithmException e) {throw new RuntimeException(" genarateRandomKey fail!", e);}/* SecureRandom random = new SecureRandom();keygen.init(random);*/keygen.init(128);Key key = keygen.generateKey();return key.getEncoded();}}

RSA加密

        上面提到会在nginx那边存储一份私钥、那么如何保证客户端(浏览器)的每一对公私玥都是能对应上的呢。这里就需要在做一个设计、就是客户端在请求公钥之前先获取一个临时的token、临时token跟正式token的区别在于临时token的权限是固定的一些URI。并且临时token中的userId是随机生成的虚拟的,临时token的时效也不用设置太长。当用户登录成功后token中的tokenId(之前提到的使用雪花字符串或者UUID)不变、只需要替换里面的userId跟重新设置redis的有效时长即可。这样nginx就可以使用token作为关键字存储每一个客户端对应的私钥了。

RSA工具类

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.*;
import java.util.HashMap;
import java.util.Map;/*** RSA处理工具类** @author hhs* @date 2019-10-22 09:54* @since JDK1.8*/
@Slf4j
public class RsaPassUtils {/*** 填充模式*/private final static String RSA_CIPHER = "RSA/ECB/OAEPWithSHA-1AndMGF1PADDING";/*** 密钥位数*/private final int KEY_SIZE = 2048;private  KeyPair KEY_PAIR;public RsaPassUtils(){try {SecureRandom random = new SecureRandom();KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");generator.initialize(KEY_SIZE, random);KEY_PAIR = generator.generateKeyPair();} catch (Exception e) {throw new RuntimeException(e);}}/*** 生成rsa公钥和私钥** @return Map {@link HashMap}: publicKey-公钥(RSAPublicKey),privateKey-私钥(RSAPrivateKey)* @author hhs* @date 2019-10-22 09:54*/public Map<String, Object> getRsaKey() {Map<String, Object> keyInfo = new HashMap<>(2);// 公钥RSAPublicKey publicKey = (RSAPublicKey) KEY_PAIR.getPublic();keyInfo.put("publicKey", publicKey);// 私钥RSAPrivateKey privateKey = (RSAPrivateKey) KEY_PAIR.getPrivate();keyInfo.put("privateKey", privateKey);return keyInfo;}/*** 生成rsa公钥和私钥** @return Map {@link HashMap}: publicKey-公钥(X509格式),privateKey-私钥(PKCS8格式)* @author hhs* @date 2019-10-22 09:54*/public Map<String, String> getX509AndPKCS8Key() {Map<String, Object> keyInfo = getRsaKey();Map<String, String> x509AndPKCS8Key = new HashMap<>(2);// 公钥RSAPublicKey publicKey = (RSAPublicKey) keyInfo.get("publicKey");
//        String rsaPublicKey = (new BASE64Encoder()).encodeBuffer(publicKey.getEncoded());String rsaPublicKey = Base64.encodeBase64String(publicKey.getEncoded());x509AndPKCS8Key.put("publicKey", rsaPublicKey);// 私钥RSAPrivateKey privateKey = (RSAPrivateKey) keyInfo.get("privateKey");
//        String rsaPrivateKey = (new BASE64Encoder()).encodeBuffer(privateKey.getEncoded());String rsaPrivateKey = Base64.encodeBase64String(privateKey.getEncoded());x509AndPKCS8Key.put("privateKey", rsaPrivateKey);return x509AndPKCS8Key;}/*** PKCS8的私钥字符串还原为RSA私钥** @param pkcs8Key {@link String} 待还原私钥字符串* @return RSAPrivateKey {@link RSAPrivateKey}* @author hhs* @date 2019-10-22 09:54*/private RSAPrivateKey getPrivateKey(String pkcs8Key) {PrivateKey privateKey = null;try {
//            byte[] decodeKey = (new BASE64Decoder()).decodeBuffer(pkcs8Key);byte[] decodeKey = Base64.decodeBase64(pkcs8Key);PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(decodeKey);KeyFactory keyFactory = KeyFactory.getInstance("RSA");privateKey = keyFactory.generatePrivate(pkcs8);} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {log.error("----------RSAUtils---------->PKCS8的私钥字符串还原为RSA私钥出错:{}", e.getMessage());}return (RSAPrivateKey) privateKey;}/*** X509的公钥字符串还原为RSA公钥** @param x509Key {@link String} 待还原公钥字符串* @return RSAPublicKey {@link RSAPublicKey}* @author hhs* @date 2019-10-22 09:54*/private RSAPublicKey getPublicKey(String x509Key) {PublicKey publicKey = null;try {
//            byte[] decodeKey = (new BASE64Decoder()).decodeBuffer(x509Key);byte[] decodeKey = Base64.decodeBase64(x509Key);X509EncodedKeySpec x509 = new X509EncodedKeySpec(decodeKey);KeyFactory keyFactory = KeyFactory.getInstance("RSA");publicKey = keyFactory.generatePublic(x509);} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {log.error("----------RSAUtils---------->X509的公钥字符串还原为RSA公钥:{}", e.getMessage());}return (RSAPublicKey) publicKey;}/*** <p>使用模和指数生成RSA公钥* 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA/None/NoPadding】* </p>** @param modulus        {@link BigInteger} 模* @param publicExponent {@link BigInteger} 公钥指数* @return RSAPublicKey {@link RSAPublicKey}* @author hhs* @date 2019-10-22 09:54*/public RSAPublicKey getPublicKey(BigInteger modulus, BigInteger publicExponent) {RSAPublicKey publicKey = null;try {KeyFactory keyFactory = KeyFactory.getInstance("RSA");RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, publicExponent);publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);log.info("----------RSAUtils---------->生成公钥:{}", publicKey);} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {log.error("----------RSAUtils---------->生成公钥异常:{}", e.getMessage());}return publicKey;}/*** <p>* 使用模和指数生成RSA私钥* 注意:【此代码用了默认补位方式,为RSA/None/PKCS1Padding,不同JDK默认的补位方式可能不同,如Android默认是RSA/None/NoPadding】* </p>** @param modulus         {@link BigInteger} 模* @param privateExponent {@link BigInteger} 私钥指数* @return RSAPrivateKey {@link RSAPrivateKey}* @author hhs* @date 2019-10-22 09:54*/public RSAPrivateKey getPrivateKey(BigInteger modulus, BigInteger privateExponent) {RSAPrivateKey privateKey = null;try {KeyFactory keyFactory = KeyFactory.getInstance("RSA");RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(modulus, privateExponent);privateKey = (RSAPrivateKey) keyFactory.generatePrivate(keySpec);} catch (Exception e) {log.error("----------RSAUtils---------->生成私钥异常:{}", e.getMessage());}return privateKey;}/*** 公钥加密** @param publicKey {@link String} X509格式公钥* @param plaintext {@link String} 明文* @return String {@link String} 密文* @author hhs* @date 2019-10-22 09:54*/public String encryptPublicKey(String publicKey, String plaintext) {RSAPublicKey rsaPublicKey = getPublicKey(publicKey);String result = "";try {byte[] bytes = encryptByRsaKey(rsaPublicKey, plaintext.getBytes());result = Base64.encodeBase64String(bytes);} catch (Exception e) {log.error("----------RSAUtils---------->公钥加密异常:{}", e.getMessage());}return result;}/*** 公钥解密** @param publicKey  {@link String} X509格式公钥* @param ciphertext {@link String} 密文* @return String {@link String} 明文* @author hhs* @date 2019-10-22 09:54*/public String decryptPublicKey(String publicKey, String ciphertext) {byte[] bytes = Base64.decodeBase64(ciphertext);RSAPublicKey rsaPublicKey = getPublicKey(publicKey);String result = "";try {result = new String(decryptByRsaKey(rsaPublicKey, bytes), StandardCharsets.UTF_8);} catch (Exception e) {log.error("----------RSAUtils---------->私钥解密异常:{}", e.getMessage());}return result;}/*** 私钥加密** @param privateKey {@link String} PKCS8格式私钥* @param plaintext  {@link String} 明文* @return String {@link String} 密文* @author hhs* @date 2019-10-22 09:54*/public String encryptPrivateKey(String privateKey, String plaintext) {RSAPrivateKey rsaPrivateKey = getPrivateKey(privateKey);String result = "";try {byte[] bytes = encryptByRsaKey(rsaPrivateKey, plaintext.getBytes());result = Base64.encodeBase64String(bytes);} catch (Exception e) {log.error("----------RSAUtils---------->公钥加密异常:{}", e.getMessage());}return result;}/*** 私钥解密** @param privateKey {@link String} PKCS8格式私钥* @param ciphertext {@link String} 密文* @return String {@link String}* @author hhs* @date 2019-10-22 09:54*/public String decryptPrivateKey(String privateKey, String ciphertext) {byte[] bytes = Base64.decodeBase64(ciphertext);RSAPrivateKey rsaPrivateKey = getPrivateKey(privateKey);String result = "";try {result = new String(decryptByRsaKey(rsaPrivateKey, bytes), StandardCharsets.UTF_8);} catch (Exception e) {log.error("----------RSAUtils---------->私钥解密异常:{}", e.getMessage());}return result;}/*** 数据分组解密** @param key                 {@link Key} RSA公钥或者私钥* @param ciphertext-密文byte数组* @return byte[] 明文byte数组* @throws Exception {@link Exception} 异常数据* @author hhs* @date 2019-10-22 09:54*/private byte[] decryptByRsaKey(Key key, byte[] ciphertext) throws Exception {// Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");Cipher cipher = Cipher.getInstance(RSA_CIPHER);cipher.init(2, key);int inputLen = ciphertext.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;for (int i = 0; inputLen - offSet > 0; offSet = i * 256) {byte[] cache;if (inputLen - offSet > 256) {cache = cipher.doFinal(ciphertext, offSet, 256);} else {cache = cipher.doFinal(ciphertext, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);++i;}byte[] decryptedData = out.toByteArray();out.close();return decryptedData;}/*** 数据分组加密** @param key                {@link Key} Rsa公钥或私钥* @param plaintext-明文byte数组* @return byte[] 密文byte数组* @throws Exception {@link Exception} 异常数据* @author hhs* @date 2019-10-22 09:54*/private byte[] encryptByRsaKey(Key key, byte[] plaintext) throws Exception {// Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");Cipher cipher = Cipher.getInstance(RSA_CIPHER);cipher.init(1, key);int inputLen = plaintext.length;ByteArrayOutputStream out = new ByteArrayOutputStream();int offSet = 0;for (int i = 0; inputLen - offSet > 0; offSet = i * 244) {byte[] cache;if (inputLen - offSet > 244) {cache = cipher.doFinal(plaintext, offSet, 244);} else {cache = cipher.doFinal(plaintext, offSet, inputLen - offSet);}out.write(cache, 0, cache.length);++i;}byte[] encryptedData = out.toByteArray();out.close();return encryptedData;}}

注意在填充时、不要在构造中添加"BC"参数,该模式配合到C语言进行解密时,C语言不好处理、所以需要将该参数去掉:

Cipher cipher = Cipher.getInstance(RSA_CIPHER,"BC");


http://chatgpt.dhexx.cn/article/SuOBwjRV.shtml

相关文章

数字信封加密

OpenSSL 是目前 PHP 甚至是整个开发圈中的数据加密事实标准&#xff0c;包括 HTTPS/SSL 在内的加密都是它的实际应用&#xff0c; OpenSSL 提供了对称和非对称加密的形式&#xff0c;也就是我们日常中最普遍的两种加密方式。 那么&#xff0c;它和 Hash 类的加密有什么不同吗&…

p7数字信封

PKCS7的数字信封格式分为两种&#xff1a;带签名的数字信封和不带签名的数字信封。由于这个数字信封的生成过程比较复杂&#xff0c;所以这两种格式比较容易记混&#xff0c;导致都搞不清楚一个数字信封里面到底是存储的什么内容了。下面我就详细的解释一下&#xff0c;这两种数…

数字信封原理

数字信封是指发送方使用接收方的公钥来加密对称密钥后所得的数据&#xff0c;其目的是用来确保对称密钥传输的安全性。采用数字信封时&#xff0c;接收方需要使用自己的私钥才能打开数字信封得到对称密钥。 数字信封的加/解密过程如图所示。甲也要事先获得乙的公钥&#xff0c;…

PKCS7数字信封简述

1、数字信封的概念 数字信封,英文是Digital Envelope,望文生义,就可以知道将需要传递的数据,通过加密的方式包裹起来。 数字信封的准确定义,在《PKCS #7: Cryptographic Message Syntax Standard》标准的第10章中给出,原话是:“加密的内容,以及对内容解密的密钥被加密…

什么是数字信封?

一、什么是数字信封 数字信封是公钥密码体制在实际中的一个应用&#xff0c;是用加密技术来保证只有规定的特定收信人才能阅读通信的内容。 在数字信封中&#xff0c;信息发送方采用对称密钥来加密信息内容&#xff0c;然后将此对称密钥用接收方的公开密钥来加密&#xff08;这…

数据来源渠道及采集工具_几款简单好用的爬虫抓取数据采集工具

新朋友点上方蓝字“Office交流网”快速关注 1. 火车头采集器 火车采集器我们也一直在用&#xff0c;是老牌的采集工具了。它不仅可做抓取工具&#xff0c;也可以做数据清洗、分析、挖掘已经可视化等工作。数据源可来源于网页&#xff0c;网页中能看到的内容和不可看到都可以通过…

爬虫抓取新浪微博数据

工具&#xff1a;云采爬虫 目标&#xff1a;抓取某个博主的全部微博 分析网页结构&#xff1a; 我们抓取的思路是模拟浏览器自动访问页面抓取。 我们来看一下页面结构&#xff0c;首先每个微博列表&#xff0c;必须进行三四次的下拉加载&#xff0c;如果底部有个翻页的按钮…

python3 爬虫抓取股市数据

python3 爬虫抓取股市数据 爬虫抓取数据的一般步骤代码运行结果小结注意事项 爬虫抓取数据的一般步骤 1、确定需要抓取的网站2、分析url&#xff0c;找到url的的变化规律3、分析页面的数据4、获取页面数据5、提取需要爬取的数据6、写入数据库或写入文件代码 import requests i…

Python_爬虫数据存入数据库(超详细过程

目录 一、新建项目 二、程序的编写 三、数据的爬取 一、新建项目 1.在cmd窗口输入scrapy startproject [项目名称] 创建爬虫项目 接着创建爬虫文件&#xff0c;scrapy genspider [爬虫名字] [爬虫域名] 打开pycharm项目&#xff0c;就可以看到生成的cblog.py文件 二、程序的…

爬虫抓取分页数据的简单实现

爬虫抓取分页数据的简单实现 昨天&#xff0c;我们已经利用Jsoup技术实现了一个简单的爬虫&#xff0c;原理很简单&#xff0c;主要是要先分析页面&#xff0c;拿到条件&#xff0c;然后就去匹配url&#xff0c;采用dome解析的方式循环抓取我们需要的数据&#xff0c;从而即可轻…

PHP爬虫抓取网页数据

2019年我接触到PHP爬虫的时候&#xff0c;我最开始是懵的。还有人用php来写爬虫&#xff1f; 一个月之后&#xff0c;嗯~全世界最好的语言写全世界最好的爬虫&#xff0c;真香&#xff01;而在7月15这一个日常加班的晚上&#xff0c;做完手头的活&#xff0c;我寻思着写会儿php…

网络爬虫的基本结构是什么?如何建立网络爬虫抓取数据?

摘要&#xff1a;互联网上有很多丰富的信息可以被抓取并转换成有价值的数据集&#xff0c;然后用于不同的行业。比如企业用户利用电商平台数据进行商业分析&#xff0c;学校的师生利用网络数据进行科研分析等等。那么&#xff0c;除了一些公司提供的一些官方公开数据集之外&…

利用EXCEL进行数据爬虫

说到爬虫&#xff0c;相信大家出现在脑海中的一定是python。python在最近几年确实热火朝天&#xff0c;对于不会编程人员来说&#xff0c;利用好EXCEL一样也可以爬取一些简单的数据&#xff0c;并且方式非常简单。 1.爬取东方财富网上基金信息。网址为&#xff1a;基金收益排行…

利用Excel数据爬虫

1、在Excel里数据里打开自网站。 2、选择高级部分 URL部分和URL预览填写为目标&#xff08;需要爬取数据的网址&#xff09;的URL地址 命令超时选择1分钟即可。 HTTP请求标头参数 第一步点击网络 第二部点击消息头部 第三部找到User-Agent的value复制 3、最后点击加载 就…

爬虫抓取网络数据时经常遇到的六种问题

随着互联网时代的不断发展&#xff0c;爬虫采集已经成为了目前最为主流的数据获取方式。使用爬虫软件自动从网站中提取数据可以节省大量的时间和精力。接下来就一起来看看爬虫抓取网络数据时经常遇到的六种问题吧&#xff1a; 1.IP阻止 IP阻止是指网站所有者主动阻止用户的IP地…

Jsoup实现网络爬虫抓取数据

Jsoup实现网络爬虫抓取数据 在编写一个软件&#xff0c;例如关于教务软件的时候&#xff0c;需要获取学校官网的一些新闻信息来充实自己的软件&#xff0c;而又不会专门提供相关的api接口&#xff0c;此时就需要我们自己动手来抓取感兴趣的信息。有人会问抓取网站的信息是否会…

Java爬虫,数据采集经验分享

公司要求我采集网页中的某些数据&#xff0c;以下是我采集的步骤和思路&#xff0c;比较基础。 一.首先我是通过抓取网页源代码的方式&#xff0c;根据源代码&#xff0c;获取各种标签中的数据 public class GetData {//数据抓取核心类// 获取网页数据/** param url:目标网址…

Python爬虫抓取数据时怎么防止ip被封

大数据公司在做数据分析的时候&#xff0c;对目标网站频繁访问很容易触发网站的反爬机制&#xff0c;因此如果想要突破限制只能使用动态ip频繁切换地址模拟真实客户访问网站才能起到防封效果。比如在做数据抓取的时候报错403等限制访问&#xff0c;大概率是因为ip被限。本文总结…

爬虫入门——数据抓取

学习爬虫&#xff0c; 最初的操作便是模拟浏览器向服务器发出请求。使用一下库实现此请求 1.urllib库的使用 urllib 库是Python 内置的HTTP 请求库&#xff0c;包含以下四个模块&#xff1a; 1.request&#xff1a;http请求模块 2.error&#xff1a;异常处理模块 3.parse&#…

ts全局变量定义

参照已有全局变量定义 src/global.d.ts /** Author: hongbin* Date: 2022-10-21 08:49:42* LastEditors: hongbin* LastEditTime: 2022-10-21 09:09:08* Description:全局类型&#xff0c;变量&#xff0c;常量*/ //全局变量 declare let Hong: string; declare const BIN: s…