Postman 的脚本简介

前言

Postman 是一款非常流行的 API 测试工具。特别是对于后端来讲,几乎是必备的工具。不过近些年也出现了一些国产的替代品,比如 ApiPostApiFox 等。我也使用过一段时间这些工具,发现了这些工具中包含了一些非常高级的功能。例如自定义的脚本、环境变量、数据驱动等。这些功能在 Postman 中也是有的,本文用来简单介绍一下 Postman 的这些功能。

概念

  • Collections - 一个 Collection 就是一个 API 的集合。可以理解为一个项目
    • folder - 一个 Collection 中可以包含多个 folder。一个 folder 中可以包含多个 folder 或 Request。
    • request - 一个 request 就是一个 API 接口。
  • Environment - 环境变量。可以理解为一个配置文件。可以在不同的环境中切换。
    • Global - 全局变量。可以在所有的环境中使用。
    • 用户创建的其他环境 - 用户可以创建多个环境,用来在不同的环境中切换。例如:开发环境、测试环境、生产环境等。
  • Pre-request Script - 请求之前执行的脚本。可以用来做一些高级的操作。例如:计算签名、生成随机的数据、处理请求的返回值等。
  • Tests - 请求之后执行的脚本。可以用来对请求的返回值进行断言、处理返回值等。

环境变量的使用

环境变量的使用非常简单。只需要在请求的 URL 或者请求的参数中使用 {{variable}} 的方式引用环境变量即可。例如:

1
2
3
4
5
6
7
curl --location '{{local_ip}}/login' \
--header 'sign: {{sign}}' \
--header 'Content-Type: application/json' \
--data '{
"user_name": "{{user_name}}",
"password": "{{password}}"
}'

内置变量和动态变量

Postman 中有一些内置的变量,使用方法和环境变量类似,但需要在变量前加 $ 符号,形如

1
{{$variable}}

完整的内置变量列表可以参考 官方文档,以下列出一些常用的内置变量:

变量名 描述 示例
$guid 以 uuid4 的规则生成一个字符串 e904c776-eb1a-4147-9986-8eb1773a8c90
$timestamp 获取当前的 10 位时间戳,单位为秒 1709082557
$isoTimestamp 获取当前 UTC 时区的时间 2024-02-28T01:11:07.768Z
$randomUUID 生成一个 36 位的随机 uuid 字符串 8bbf62ed-ade6-4b6c-8535-a99daea521ca
$randomInt 生成一个 0 - 1000 的随机数 51
$randomBoolean 生成一个随机的布尔值 true
$randomIP 生成一个随机的 ip v4 的地址 28.248.146.132
$randomIPV6 生成一个随机的 ip v6 的地址 f148:7ca0:007d:6cd9:db02:a504:3116:9daf

脚本

脚本官方手册

Postman 中的脚本是使用 JavaScript 编写的。脚本可以在请求的各个阶段执行。例如:在请求之前执行、请求之后执行、请求失败时执行等。脚本可以用来做一些高级的操作,例如:计算签名、生成随机的数据、处理请求的返回值等。

postman 提供了一个 pm 对象用来对 postman 中的数据进行操作。例如:获取环境变量、设置环境变量、获取请求的返回值等。

相关的支持非常多。有需要了可以通过官方手册进行查询。以下给出一个计算请求 RSA 签名的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// 获取jsRSA的库
let jsUrl = "https://gitee.com/lzq1357/various/raw/master/forge_min.js"
if (!pm.globals.has('forgeJS')) {
pm.sendRequest(jsUrl, function (err, res) {
if (err) {
console.error(err);
} else {
pm.globals.set('forgeJS', res.text());
console.info("request forgs.js: Succeed, please try again");
}
}
);
} else {
eval(pm.globals.get('forgeJS'));
}

let privateKey = "your_private_key"

var crypto = require('crypto-js');

// 读取body数据
let requestBody = JSON.parse(pm.request.body.raw);

// 如果密码是明文,进行 hash , 仅针对登录
if (requestBody.hasOwnProperty("password")) {
if (requestBody.password.length != 32) {
requestBody.password = crypto.MD5(requestBody.password).toString();
console.log(requestBody.password)
pm.request.body.raw = JSON.stringify(requestBody);
pm.request.body.update(pm.request.body);
}
}

let requestStr = JSON.stringify(requestBody)


// // 生成需要进行签名的字符串 & 拼接参数
// let requestStr = ""
// Object.entries(requestBody).forEach(([key, value]) => {
// requestStr += key + "=" + value + "&"
// });

//计算SHA256
// signStr = crypto.SHA256(requestStr).toString()
//计算md5
// console.log(crypto.MD5("123456").toString())

// const sign = crypto.createSign('SHA256');
// sign.update(signStr);
// const signature = sign.sign(privateKey, 'base64');
// console.log(signature)

//计算签名
const md = forge.md.sha256.create();
var prk = forge.pki.privateKeyFromPem(privateKey);
md.update(requestStr, "utf8");
var sign64 = prk.sign(md);
var sign = forge.util.encode64(sign64)

// 将计算的签名设置到全局变量中
pm.globals.set("sign", sign)