apipost下载安装教程、脚本详细使用教程

目录

apipost脚本使用教程

缘由:

实现流程:

1、设置接口需要的URL:

2、boby:

3、预执行操作:

4、断言

5、执行结果:

什么是ApiPost?

下载以及安装:

apipost使用文档介绍:

发送前动态修改Query、Body、Header参数

1、使用场景​

2、脚本语法

3、实际项目操作例如

利用预执行脚本动态添加一个请求参数

使用场景​

body请求参数如下:​

header请求参数如下:​

具体实现​

1、计算token并赋给变量​

2、动态添加请求头​

3、实际项目操作例如

请求一个需要登录才能访问的接口(基于COOKIE)

方案I、开启全局cookie​

方案II、利用环境变量,先请求登陆接口,再请求后续接口​

利用CryptoJS对请求参数进行MD5、AES加解密

MD5加密​

SHA256加密​

base64加密​

base64解密​

AES简单加密​

AES简单解密​

自定义AES加解密函数​

请求示例​

请求接口自动计算参数签名

使用场景​

脚本语法​

实际项目操作例如

如何使用断言

什么是断言​

使用 Apipost 的断言格式​

响应结果的校验

数据校验的意义​

数据校验的设置​

常见问题​


apipost脚本使用教程

缘由:

本期文章主要围绕脚本实现模拟第三方推送接口讲解

主要原因:项目涉及到需要对接第三方接口,暴露接口出去给第三方调用。每次项目订单状况节点,需要等待第三方开单后,在推送下单状态回来,每次多人操作时候,都需要登录同一账号,过程等待比较缓慢,效率比较低。

实现流程:

1、设置接口需要的URL:
http://localhost:8080/api/dbts/sendOrderStatus
2、boby:

参数名

参数值描述
digest

String

{{digest}}

params

String

{{params}}

timestamp

String

1731572100579

companyCode

String

{{companyCode}}

logisticID

String

TSVU43434t318000045

mailNo

String

sdferee340985266

statusType

String

GOT

3、预执行操作:
class SecurityUtil {static getDigest(plainText) {// 使用 crypto 模块生成 MD5 哈希let md5Str = CryptoJS.MD5(plainText);// 将 MD5 哈希转换为 Base64 编码的字符串let base64Encoded = btoa(md5Str);return base64Encoded;}
}let timestamp = request.request_bodys.timestamp.toString();
apt.globals.set("timestamp", timestamp);let companyCode = "*********"; //账号编码
apt.globals.set("companyCode", companyCode);let appkey = "********************"; //账密let params = "";
let logisticID = request.request_bodys.logisticID.toString();
let mailNo = request.request_bodys.mailNo.toString();
let statusType = request.request_bodys.statusType.toString();
console.log("logisticID: " + logisticID + " ,mailNo: " + mailNo + " ,statusType: " + statusType );
apt.removeRequestBody("logisticID");
apt.removeRequestBody("mailNo");
apt.removeRequestBody("statusType");
const model = packingCommonModel();
params = JSON.stringify(model);
apt.globals.set("params", params);let digest = "";
digest = SecurityUtil.getDigest(params + appkey + timestamp);
console.log("digest: ", JSON.stringify(digest));
apt.globals.set("digest", digest);function packingCommonModel() {const commonModel = {gmtUpdated: "1724375950500",logisticCompanyID: "DEPPON",logisticID: logisticID,mailNo: mailNo,statusType: statusType};return commonModel;
}
4、断言

后执行操作:

apt.test("响应json的errstr字段值为'success'", function () {var jsonData = apt.response.json();apt.expect(jsonData.errstr).to.eql("success");
});apt.test("成功的POST请求", function () {apt.expect(apt.response.code).to.be.oneOf([201, 202]);
});
5、执行结果:

断言与校验结果:

什么是ApiPost?

Apipost 基于同一份数据源,同时提供供后端开发、前端开发、测试人员使用的接口调试、Mock、自动化测试等功能,实时协作,降本增效绝不是空谈!

同时,针对技术管理层来说,也大大方便了 API 文档类数字资产的管理与延续。

视频教程:ApiPost视频培训教程

下载以及安装:

支持Windows、Mac、Linux等多种操作系统

下载地址: 
apipost下载地址

下载后,直接解压安装就OK了。如果对安装有问题的朋友,各位自行百度一下!!!

apipost使用文档介绍:

https://v7-wiki.apipost.cn/docs/4

发送前动态修改Query、Body、Header参数

在文档 “预执行脚本” 中,我们了解到,预执行脚本的作用主要是:

编写JS函数等实现复杂计算;
变量的打印
定义、获取、删除、清空环境变量
定义、获取、删除、清空全局变量
获取请求参数
动态添加、删除一个header请求参数
动态添加、删除一个query请求参数
动态添加、删除一个body请求参数
发送HTTP请求

利用这个功能,我们可以在发送前动态的添加或者修改请求参数。

1、使用场景​

适用于在请求发送前,需要动态改变请求参数的情况。例如:请求发送时,需要通过其他请求参数计算一个token同时添加到对应的发送参数中。

2、脚本语法

apt.setRequestQuery("key", "value"); // 给URL添加、修改query参数
apt.removeRequestQuery("key"); // 删除URL的指定query参数
apt.setRequestHeader("key", "value"); // 增加、修改一个请求头key
apt.removeRequestHeader("key"); // 删除请求头 key
apt.setRequestBody("key", "value"); // 增加、修改一个body参数
apt.removeRequestBody("key"); // 删除body参数key
apt.setRequestBody({ "key": "value" }
); // 将 body 参数 "整体" 重置为 {"key": "value"},适用于原请求体为 raw 类型的情况

3、实际项目操作例如

totalVolume 和 totalWeight 获取值之后,需要在请求体删除掉

脚本

let totalVolume = request.request_bodys.totalVolume.toString();
let totalWeight = request.request_bodys.totalWeight.toString();
apt.removeRequestBody("totalVolume");
apt.removeRequestBody("totalWeight");

利用预执行脚本动态添加一个请求参数

使用场景​

我们可能需要在请求时发送一些参数,而这些参数是通过其他参与发送的请求参数计算而来的。举例:

body请求参数如下:​
参数参数描述
user_id用户id
nick_name用户名
header请求参数如下:​
参数参数描述
token由body的请求参数user_id、nick_name通过md5 加密后组成

如上面的情况,我们需要在发送前,先通过body的请求参数user_id、nick_name通过md5 加密计算得出一个token放到header里才行。ApiPost如何实现这个需求呢?

我们可以通过在预执行脚本里增加请求参数来实现。

具体实现​

如下图,我们已经在body里添加好了我们需要的参数。

1、计算token并赋给变量​

我们接下来要做的是通过预执行脚本计算出token并添加到header参数。

先在预执行脚本里定义一个临时变量raw_token,其值由

let raw_token = $.md5(request.request_bodys.user_id.toString() + request.request_bodys.nick_name.toString());

其中的含义为:定义一个变量raw_token,其值等于

$.md5(request.request_bodys.user_id + request.request_bodys.nick_name)

注:$.md5 是APIPOST脚本内置的md5函数。更多加密函数可以参考 “利用CryptoJS对请求参数进行MD5/AES加解密” 一节。

2、动态添加请求头​
apt.setRequestHeader("token", raw_token);

发送后,可以看到APIPOST自动添加了一个请求头token

3、实际项目操作例如
mailNo

String

sdferee340985266

statusType

String

GOT

脚本:

let mailNo = request.request_bodys.mailNo.toString();
let statusType = request.request_bodys.statusType.toString();
console.log(mailNo: " + mailNo + " ,statusType: " + statusType );

请求一个需要登录才能访问的接口(基于COOKIE)

在后台在开发、调试接口时,常常会遇到需要登陆才能请求的接口。

比如:获取登陆用户的收藏列表,此时,我们就需要模拟登陆状态进行接口调试了。如图:

markdown picture

 .png)

今天,我们讲解利用ApiPost的环境变量,解决这种需要先登录再请求的接口依赖情况。

ApiPost提供了2种方案:

方案I、开启全局cookie​

apipost提供了开启全局cookie的功能。开启路径如下:

右下角Cookie管理器-打开全局Cookie按钮

markdown picture

开启后,我们请求登陆接口后,后续接口都会共享“已登陆”的状态,即共享了登陆接口返回的cookie。

如下所示:

第一步:请求登陆接口​

markdown picture

第二步:访问其他接口,则都处于了登陆状态​

markdown picture

方案II、利用环境变量,先请求登陆接口,再请求后续接口​

这种方案是针对关闭了全局cookie功能的情况。

1、请求登陆接口,将响应COOKIE赋值给变量:​

为了处于登陆态,需要先请求登陆接口,此举目的是为了模拟用户的登陆行为,获取需要的登陆参数(这里是Cookie)。

将登陆接口返回的PHPSESSID(这个是SessionID,PHPSESSID是针对PHP作为后端接口的SessionID变量名,其他语言的变量名可能不同)设为环境变量。

apt.variables.set("login_var", response.cookies["PHPSESSID"]);

注:更多响应结果绑定变量可以参考 “响应以及断言”一节和“后执行脚本” 一节。

markdown picture

2、调用变量,手动给header添加Cookie参数​

接着返回收藏接口,进到header选项,参数值选择cookie,参数值输入: PHPSESSID={{login_var}}。

此举是为了利用登陆接口返回的Cookie伪造请求的PHPSESSID。

如图:

markdown picture

或者你也可以定义个全局header,这样就不用每个接口都设置一遍了:

markdown picture

markdown picture

登录实现原理​

利用ApiPost发送Cookie,使服务器识别已登录用户的Cookie。

利用CryptoJS对请求参数进行MD5、AES加解密

ApiPost内置了CryptoJS( GitHub - brix/crypto-js: JavaScript library of crypto standards. ) ,可以方便的对请求参数进行各种加解密。

MD5加密​

CryptoJS.MD5('待加密字符串').toString()

image

SHA256加密​

image

base64加密​

CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse('待加密字符串'))

image

base64解密​

CryptoJS.enc.Base64.parse("待解密字符串").toString(CryptoJS.enc.Utf8)

image

AES简单加密​

CryptoJS.AES.encrypt('待加密字符串', '秘钥').toString()

image

AES简单解密​

CryptoJS.AES.decrypt('待解密字符串', '秘钥').toString(CryptoJS.enc.Utf8)

image

自定义AES加解密函数​

以上示例是2个简单aes加解密方案,大部分情况下,我们需要自定义aes加解密更多的参数,比如加密模式、填充等。

const key = CryptoJS.enc.Utf8.parse("秘钥");  //十六位十六进制数作为密钥
const iv = CryptoJS.enc.Utf8.parse('偏移量');   //十六位十六进制数作为密钥偏移量//解密方法
function Decrypt(word) {let encryptedHexStr = CryptoJS.enc.Hex.parse(word);let srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);let decrypt = CryptoJS.AES.decrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8);return decryptedStr.toString();
}//加密方法
function Encrypt(word) {let srcs = CryptoJS.enc.Utf8.parse(word);let encrypted = CryptoJS.AES.encrypt(srcs, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 });return encrypted.ciphertext.toString().toUpperCase();
}//以上方法中 mode就是加密模式,padding是填充。
请求示例​

image

请求接口自动计算参数签名

使用场景​

某些接口需要通过参数签名验证接口请求合法性。 例如签名规则如下:将请求参数param1, param2,按照appid+param1+parma2+salt+secretKey 的顺序拼接得到字符串1。 第二步:对字符串1做md5,得到32位小写的sign。

脚本语法​

使用预执行脚本实现这个需求,实现demo如下

// 获取 query 参数 param1, param2
var queryParams = request.request_querys;
console.log(queryParams);
var param1 = queryParams['param1'];
var param2 = queryParams['param2'];// 获取预先设置为环境变量的 APPID 和 SECRET_KEY
var appid = apt.variables.get("APPID");
var secretKey = apt.variables.get("SECRET_KEY");// 定义一个随机数(11111 65536)之间
var salt = parseInt(Math.random() * (54425) + 11111, 10);// 将随机数转换为字符串
salt = salt.toString();
console.log(salt);// 定义一个由appid、要翻译的字符串、随机数、密钥组合成一个字符串
var str = appid + param1 + param2 + salt + secretKey;
console.log(str);// 将 str 进行 md5 加密生成 sign
var sign = CryptoJS.MD5(str).toString();apt.setRequestQuery("salt", salt); //设置salt
apt.setRequestQuery("sign", sign); //设置签名

实际项目操作例如

boby:

脚本:

class SecurityUtil {static getDigest(plainText) {// 使用 crypto 模块生成 MD5 哈希let md5Str = CryptoJS.MD5(plainText);// 将 MD5 哈希转换为 Base64 编码的字符串let base64Encoded = btoa(md5Str);return base64Encoded;}
}let timestamp = request.request_bodys.timestamp.toString();
apt.globals.set("timestamp", timestamp);let companyCode = "*********"; //账号编码
apt.globals.set("companyCode", companyCode);let appkey = "********************"; //账密let params = "";
let logisticID = request.request_bodys.logisticID.toString();
let mailNo = request.request_bodys.mailNo.toString();
let statusType = request.request_bodys.statusType.toString();
console.log("logisticID: " + logisticID + " ,mailNo: " + mailNo + " ,statusType: " + statusType );
apt.removeRequestBody("logisticID");
apt.removeRequestBody("mailNo");
apt.removeRequestBody("statusType");
const model = packingCommonModel();
params = JSON.stringify(model);
apt.globals.set("params", params);let digest = "";
digest = SecurityUtil.getDigest(params + appkey + timestamp);
console.log("digest: ", JSON.stringify(digest));
apt.globals.set("digest", digest);function packingCommonModel() {const commonModel = {gmtUpdated: "1724375950500",logisticCompanyID: "DEPPON",logisticID: logisticID,mailNo: mailNo,statusType: statusType};return commonModel;
}

打印结果:

如何使用断言

什么是断言​

断言一般用于 后执行脚本 用来校验响应结果是否符合预期。

在协作开发、版本升级、服务器升级、接口返回的过程中,有可能因为一些bug,和我们预期的结果不一致。为了便于开发&测试人员能够更快的发现bug,保证整个产品的质量以及进度,于是我们推出了断言功能。

  1. 定义测试用例
  1. 验证测试用例

例如接口返回:

{"errcode": 0,"errstr": "success","post": {"body": "test"},"get": [],"request": {"body": "test"},"file": [],"put": "","header": {"User-Agent": "ApiPOST Runtime +https://www.apipost.cn","Accept": "*/*","Accept-Encoding": "gzip, deflate, br","Connection": "keep-alive","Hello": "Tom","Cookie": "cookie-test5=nihao;cookie-test1=0;cookie-test2=0;cookie-test8=renge;cookie-test3=%25E4%25BD%25A0%25E5%25A5%25BD;cookie-test4=%E4%BD%A0%E5%A5%BD;httponly-cookie=httponly-value","Host": "echo.apipost.cn","Content-Type": "multipart/form-data; boundary=--------------------------856985481572999749293071","Content-Length": "163"},"cookie": {"cookie-test5": "nihao","cookie-test1": "0","cookie-test2": "0","cookie-test8": "renge","cookie-test3": "%E4%BD%A0%E5%A5%BD","cookie-test4": "你好","httponly-cookie": "httponly-value"},"bigint": 248963637882912768
}

定义测试用例:

apt.assert('response.raw.status==200');
apt.assert('response.raw.type=="json"');
apt.assert('response.json.errcode==0');
apt.assert('response.raw.responseTime<100');
apt.assert('response.json.header.Host=="echo.Apipost.cn"');

点击发送按钮后:

image.png

绿色表示测试通过,红色表示测试不通过。

特别注意:==每个测试用例是一行,不能换行。==

例:apt.assert('response.json.header.Host=="echo.Apipost.cn"');

1)response.json.header.Host 表示响应json下面的header数组中的Host字段,
2)必须都为1,才会通过。

常见的测试断言可以通过后执行脚本获取: (常用断言示例)

image.png

使用 Apipost 的断言格式​

// 检查response body中是否包含某个string
apt.assert('response.raw.responseText=="test"');  // 检查响应文本是否等于test字符串 apt.assert('response.raw.responseText.indexOf("test") > -1');  // 检查响应文本是否含有test字符串// 检测返回JSON中的某个值是否等于预期的值
apt.assert('response.json.hasOwnProperty("errcode")'); // 检测返回json对象的是否含有errcode字段
apt.assert('response.json.errcode=="success"');  // 检测返回json对象的errcode字段是否等于success字符串
apt.assert('response.json.errcode.indexOf("success") > -1');  // 检测返回json对象的errcode字段是否含有success字符串
apt.assert('response.json.errcode!="success"');  // 检测返回json对象的errcode字段是否不等于success字符串
apt.assert('response.json.errcode>=1');  // 检测返回json对象的errcode字段是否大于1
apt.assert('response.json.errcode==null'); // 检测返回json对象的errcode字段是否是null// 测试response Headers中的某个元素是否存在(如:Content-Type)
apt.assert('response.headers.hasOwnProperty("content-type")');// 验证Status code(响应码)的值是不是等于200
apt.assert('response.raw.status==200');// 验证Response time(请求耗时)是否大于某个值
apt.assert('response.raw.responseTime>=100');

响应结果的校验

数据校验的意义​

我们可以通过 json-schema 预先定义接口的数据返回格式,当接口完成后,我们可以通过匹配 实际响应结果 和 预先定义的接口格式 ,来发现接口问题。如下图:

image.png

数据校验的设置​

我们可以通过在 设计 - 预定义响应期望 - json-schema 预先定义接口的数据返回格式。如下图:

image.png

常见问题​

注意

有用户问,为什么我返回的内容明明是 json 格式,而数据校验提示 : 返回数据格式不是json

image.png

这是因为虽然您返回的内容是 JSON 字符串,但是返回的格式却是其他类型(可以具体查看响应头的 content-type)。相当于明明是一张图片内容,您却保存为了 .txt 格式一样的道理。

本文章编辑到处结束,希望对各位有帮助!!!

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

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

相关文章

Python Web 应用开发基础知识

Python Web 应用开发基础知识 引言 随着互联网的快速发展&#xff0c;Web 应用程序的需求日益增加。Python 作为一种简单易学且功能强大的编程语言&#xff0c;已经成为 Web 开发中广受欢迎的选择之一。本文将深入探讨 Python Web 开发的基础知识&#xff0c;包括常用框架、基…

SpringBoot多环境+docker集成企业微信会话存档sdk

SpringBoot多环境docker集成企业微信会话存档sdk 文章来自于 https://developer.work.weixin.qq.com/community/article/detail?content_id16529801754907176021 SpringBoot多环境docker集成企业微信会话存档sdk 对于现在基本流行的springboot环境&#xff0c;官方文档真是比…

在openi平台 基于华为顶级深度计算平台 openmind 动手实践

大家可能一直疑问&#xff0c;到底大模型在哪里有用。 本人从事的大模型有几个方向的业务。 基于生成式语言模型的海事航行警告结构化解析。 基于生成式语言模型的航空航行警告结构化解析。 基于生成式生物序列&#xff08;蛋白质、有机物、rna、dna、mrna&#xff09;的多模态…

【论文分享】基于街景图像识别和深度学习的针对不同移动能力老年人的街道步行可达性研究——以南京成贤街社区为例

全球老龄化趋势加剧, 许多城市中老年人数量不断增加&#xff0c;而现有街道和社区基础设施往往未能满足其步行安全和便利需求。本次我们给大家带来一篇SCI论文的全文翻译&#xff0c;该论文通过探讨不同步行能力的老年人对城市步行环境的需求&#xff0c;提供了关于如何改善城市…

Android Osmdroid + 天地图 (二)

Osmdroid 天地图 &#xff08;二&#xff09; 前言正文一、定位监听二、改变地图中心三、添加Marker四、地图点击五、其他配置① 缩放控件② Marker更换图标③ 添加比例尺④ 添加指南针⑤ 添加经纬度网格线⑥ 启用旋转手势⑦ 添加小地图 六、源码 前言 上一篇中我们显示了地图…

CSS基础知识04

文本溢出通常是指在限定的空间内不能容纳所输入的文字&#xff0c;导致文字超出了容器的边界 一、文本溢出 1.1.css属性处理 所用到的属性 属性属性值overflowvisible&#xff1a;默认值&#xff0c;内容不会被修剪&#xff0c;会呈现在元素框之外。hidden&#xff1a;内容会…

gitlab和jenkins连接

一&#xff1a;jenkins 配置 安装gitlab插件 生成密钥 id_rsa 要上传到jenkins&#xff0c;id_rsa.pub要上传到gitlab cat /root/.ssh/id_rsa 复制查看的内容 可以看到已经成功创建出来了对于gitlab的认证凭据 二&#xff1a;配置gitlab cat /root/.ssh/id_rsa.pub 复制查…

Modbus TCP转Modbus ASCII解决方案

Modbus TCP和Modbus ASCII是两种不同的通信协议。Modbus TCP是一种二进制协议&#xff0c;Modbus ASCII是一种基于文本的协议。二者不能直接转换&#xff0c;因为它们的数据表示方式、消息结构、字符编码等都不相同。 如果你需要将Modbus TCP转换为Modbus ASCII&#xff0c;你…

十三、注解配置SpringMVC

文章目录 1. 创建初始化类&#xff0c;代替web.xml2. 创建SpringConfig配置类&#xff0c;代替spring的配置文件3. 创建WebConfig配置类&#xff0c;代替SpringMVC的配置文件4. 测试功能 1. 创建初始化类&#xff0c;代替web.xml 2. 创建SpringConfig配置类&#xff0c;代替spr…

全新升级!立迈胜STMP57系列防水一体化步进伺服电机:IP65+多圈绝对值编码器+EtherCAT通信+内置刹车

在这个科技日新月异的时代&#xff0c;每一步创新都意味着行业的一次飞跃。 回想当初&#xff0c;我们做防水电机的初衷只是因为客户的应用场景涉水&#xff0c;从而定做了IP65防护等级的一体式电机。 后来发现很多客户也有类似的需求&#xff0c;比如机械加工、户外照明、自…

5G CPE:为什么活动会场与商铺的网络成为最新选择

在快节奏的现代社会中&#xff0c;无论是举办一场盛大的活动还是经营一家繁忙的商铺&#xff0c;稳定的网络连接都是不可或缺的基石。然而&#xff0c;面对复杂的布线难题或高昂的商业宽带费用&#xff0c;许多场所往往陷入两难境地。幸运的是&#xff0c;5G CPE&#xff08;Cu…

React-redux 实战案例,自定义useSelector

创建一个新的 React 工程&#xff0c;并配置 Redux 和 Ant Design&#xff0c;你可以按以下步骤操作。我将使用 create-react-app 脚手架工具来快速创建一个基于 TypeScript 的 React 项目 1. 创建新项目 使用 create-react-app 创建一个新的 React 项目&#xff0c;带 TypeS…

【C++】list 类深度解析:探索双向链表的奇妙世界

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 如果你对string&#xff0c;vector还存在疑惑&#xff0c;欢迎阅读我之前的作品 &#xff1a; 之前文章&#x1f525;&#x1…

uniapp如何i18n国际化

1、正常情况下项目在代码生成的时候就已经有i18n的相关依赖&#xff0c;如果没有可以自行使用如下命令下载&#xff1a; npm install vue-i18n --save 2、创建相关文件 en文件下&#xff1a; zh文件下&#xff1a; index文件下&#xff1a; 3、在main.js中注册&#xff1a…

VScode-Java开发常用插件

中文——界面易读 字体主题——代码可观 头注释——项目信息明了 java开发包——java必备 git协作开发——版本控制

前端(3)——快速入门JaveScript

参考&#xff1a; 罗大富 JavaScript 教程 | 菜鸟教程 JavaScript 教程 1. JaveScript JavaScript 简称 JS JavaScript 是一种轻量级、解释型、面向对象的脚本语言。它主要被设计用于在网页上实现动态效果&#xff0c;增加用户与网页的交互性。作为一种客户端脚本语言&#…

FRP 实现内网穿透

如何通过 FRP 实现内网穿透&#xff1a;群晖 NAS 的 Gitea 和 GitLab 访问配置指南 在自建服务的过程中&#xff0c;经常会遇到内网访问受限的问题。本文将介绍如何利用 FRP&#xff08;Fast Reverse Proxy&#xff09;来实现内网穿透&#xff0c;以便在外网访问群晖 NAS 上的…

我们来学mysql -- EXPLAIN之select_type(原理篇)

EXPLAIN之select_type 题记select_type 题记 书接上文《 EXPLAIN之ID》2024美国大选已定&#xff0c;川普剑登上铁王座&#xff0c;在此过程中出谋划策的幕僚很重要&#xff0c;是他们决定了最终的执行计划在《查询成本之索引选择》中提到&#xff0c;explain的输出&#xff0…

uni-app快速入门(五)--判断运行环境及针对不同平台的条件编译

一、判断运行环境 在实际项目开发中&#xff0c;经常需要进行开发环境和生产环境的切换&#xff0c;uni-app可根据process.env.NODE_ENV判断当前运行环境是开发环境和生产环境&#xff0c;根据不同的环境调用不同的后台接口&#xff0c;具体实现方式: 在项目的static目录下建…

北京大学c++程序设计听课笔记101

基本概念 程序运行期间&#xff0c;每个函数都会占用一段连续的内存空间。而函数名就是该函数所占内存区域的起始地址&#xff08;也称“入口地址”&#xff09;。我们可以将函数的入口地址赋给一个指针变量&#xff0c;使该指针变量指向该函数。然后通过指针变量就可以调用这个…