问题

Postman 想必大家已经很熟悉了,本文不做过多介绍。在文章开始之前,请允许我提出以下几个问题。如果这些问题您都了然,请迅速关闭这个页面并立马去做更重要的事情。

  1. Postman 中如何设置路径参数
    • 例: GET /posts/{id},如何为 id 字段赋值。
  2. Postman 中的变量的作用域有哪些?
  3. Postman 中如何修改 HTTP 请求报文?
    1. 例1:对请求参数进行重排序并生成签名
    2. 例2:对请求参数进行加密
  4. Postman 中如何完成链式调用?
    • 例1:一键操作,串行调用xx列表接口、xx详情接口。
    • 例2:在调用业务接口之前,先从公共接口中获取 token 字段。
  5. Postman 中如何校验和遴选 HTTP 响应报文?
    1. 例1:如何对响应报文进行校验
    2. 例2:如何使用可视化的方式,高亮显示关键数据?

如果你对上述问题抱有好奇,那好,我们今天便来聊聊 Postman 中一些被不为人知却非常有用的功能。

利益不相关声明:

本文采用「和风天气API」与「心知天气API」进行讲解示范。

在互联网愈加封闭的今天,很庆幸仍有这些不忘初心的企业为我们提供如此简单易得的接口服务。

正文

1. PathParam 路径参数

RESTful 形式的接口通常会有一些参数被放置在 URL 中。例如:GET /posts/1,其中的 1 表示 post 的 ID。

Postman 虽未提供明显的 UI 界面来设置路径参数,但我们可以在 URL 输入栏中以:params的形式来添加路径参数,如下所示。

2022-03-26 at 0.42.20 - Pink Constrictor

2. Variables 变量

变量是 Postman 中最实用的功能之一,我们可以通过预定义变量来复用 API 中的参数等内容,如 BaseURL、Auth、Token 。

Postman 中的变量可分为全局变量集合变量环境变量局部变量四种类型,每种类型的作用域和优先级都有所不同,具体情况如下表所示。

变量类型作用域访问性优先级(数值越大,优先级越高)
Global-全局变量当前工作空间可被当前工作空间的任何元素访问1
Collection-集合变量某个集合内部仅限集合内部访问2
Enviroment-环境变量当前工作空间可被当前工作空间的任何元素访问3
Local-局部变量某个请求内部仅限请求自身访问4

2.1 变量冲突问题

当多个作用域同时存在相同名称的变量时,会产生变量冲突问题。遇到这种问题时,Postman 会选取优先级最高的那个作用域中的变量的值。

例如:

全局变量集合变量同时存在名为 BASE_URL 的变量时:

  • 其中全局作用域中该变量的值为 api.example.com/global

  • 其中集合作用域中该变量的值为 api.example.com/collection

那么 Postman 将使用集合变量中的 api.example.com/collection,原因是集合变量的优先级为2,比全局变量的优先级 1 高。

2.2 集合变量的写与读

本小节以集合变量进行快速演示,熟悉的老鸟可直接跳过。

设置集合变量

CollectionVariables

读取变量

Read-Variables

2.3 善用环境变量

日常开发时,通常会接触多个调试环境,如:开发环境,测试环境,灰度环境,生产环境等,不同环境的 URL 或密钥等可能不尽相同。对于这种情况,Postman 的环境变量便可派上用场。

下边将以和风天气 API 的 BASE_URL 为例,向大家演示一下环境变量的用法。如果看官您对这块比较熟悉,请忽略这一小节并进入下一章节。

添加多个环境

Env-Vairalbles

在上图中,我在 Postman 的环境管理中添加了两个环境,分别对应和风天气 API 的商业版和开发版。从图中的标记处可以看到,这两个版本的二级域名地址存在显著区别。

选择当前环境

如图所示,Postman 提供了便捷的 UI 界面用于环境变量的查看与切换。

EnviromentVarialable2

Postman 每次请求前,都会尝试从当前的环境变量获取最新的 BASE_URL 进行请求。因此,当我们需要切换环境时,只需要点一下鼠标,就能够同时影响到所有使用了BASE_URL这个变量的接口。

这个功能对于经常在同一个系统的多个环境之间穿梭的小伙伴非常有用,学会这一招,哪怕环境再翻十倍也不怕😊。

3. Scripts 脚本

Postman 中的脚本功能同样非常强大,但遗憾的很少有人知道该如何利用它。实际上,Postman 内置了一个基于 Node 的 JS 运行时环境,并以拦截器的形式向用户暴露了两个切入点,分别为 pre-request scripttest script,如图所示:

Postman-Script

这里提供一个简单的表格以便各位看官快速了解。

Postman 脚本类型调用时机典型使用场景
pre-request script请求发送之前修改请求数据,例如:对请求数据进行签名,加密等
test script收到响应之后验证响应数据,例如:验证状态码,验证报文数据格式
解密响应数据,例如:对响应报文中的敏感字段进行解密

3.1 脚本的执行顺序

与变量类似,脚本也可以在多个地方进行定义,如集合、文件夹、单个请求,当遇到多个脚本并存时,Postman 将以下图的顺序执行脚本。

Postman-Script2

3.2 脚本沙盒环境简介

Postman 为脚本的运行环境提供了丰富的功能

pm 对象常用字段与函数

  1. pm.variables.get("SOME_KEY") 按优先级读取变量
  2. pm.collectionVairables.get("SOME_KEY"),无视优先级,从集合变量中读取变量
  3. pm.enviroment.get("SOME_KEY"),无视优先级,从环境变量中读取变量
  4. pm.enviroment.name, 获取当前环境名称
  5. pm.request,获取请求对象
    1. pm.request.headers,获取请求头
    2. pm.request.url,获取请求URL
      1. pm.request.url.query,获取请求 Query 参数
    3. pm.request.body,获取请求体
    4. pm.request.method,获取请求方式
  6. pm.response,获取响应对象
    1. pm.response.headers,获取响应头
    2. pm.response.code,获取响应码
    3. pm.response.status,获取响应码文字描述
    4. pm.response.responseTime,获取响应耗时
    5. pm.response.responsseSize,获取响应大小
    6. pm.response.text(),获取响应 body(字符串格式)
    7. pm.response.json(),获取响应 body(JSON格式)
  7. pm.test,单元测试
  8. pm.visualizer,数据可视化工具

内置三方库

下面仅列出一些常用的工具库,完整列表请查看这个链接

  1. JSON 校验器:ajvtv4
  2. 断言工具库:chai
  3. jQuery 选择器:cheerio
  4. 加密套件:crypto-js
  5. 辅助工具:lodash
  6. 时间库:moment

3.3 前置脚本的使用场景

本小节以下列两个案例抛砖引玉

  1. 使用前置脚本对请求参数重排序并完成签名

  2. 使用前置脚本进行链式串行调用

3.3.1 对请求参数进行签名

简介

在一些数据敏感的业务系统中,为了避免服务被恶意调用或攻击,通常会采用签名与验签的方式来保证接口的安全性与可靠性。典型的签名和验签的流程如下所示:

  1. 接口调用端:
    1. 将请求参数按照特定的格式进行转换,然后基于时间或密钥进行某种运算并得到一个值,称为签名1
    2. 签名1连同其他请求参数一并提交给接口服务端,发起请求
  2. 接口服务端:
    1. 当服务端接收到调用端的请求时,以同样的格式和运算方法对请求参数进行处理和计算,得到另一个值,称为签名2.
    2. 对比签名1签名2是否相等
      1. 如果两者相等,则验签通过,进入后续处理。
      2. 否则出发验签失败异常,并立即输出 401。

实例

心知天气 API和风天气API 都提供了数字签名的认证机制,用来规避开发者 appKey 的泄漏问题。具体的签名及认证方法可以从以下链接中查看:

  1. 心知天气V3-签名验证方式
  2. 和风天气-加密签名认证

鉴于和风天气的文档过于晦涩,本章采用心知天气V3的签名机制进行演示。

心知天气V3 的签名方式说明


签名指的是通过 HMAC-SHA1,对请求参数加密后得到的签名字串进行身份验证,避免了将“私钥”明文包含在请求中而造成泄露。

签名的生成方式如下:

  1. 构造验证参数字符串

将请求参数按照参数名字典升序排列后,把ts、ttl(可不写)、uid参数的 param=value 用&连接起来,类似 URI 中 QueryString 的构造方式。目前支持的参数有:UNIX 时间戳ts(单位为秒,转换成字符串长度为 10 位,不要用毫秒值)、签名失效时间ttl(单位为秒,缺省为 1800,可选)和公钥uid。例:ts=1443079775&ttl=300&uid=your_public_key

  1. 使用 HMAC-SHA1 方式,以 API 密钥中的“私钥”对上一步生成的参数字符串进行加密

常见程序语言通常会内置加密函数,或通过扩展库提供支持。例如在 NodeJS 中,您可以使用crypto模块中的中的createHmac函数,例:crypto.createHmac(“sha1”, your_private_key)。

  1. 将上一步生成的加密结果用 Base64 编码,并做一个 URLEncode,得到签名 sig

步骤(1)中的参数例子用 base64 编码后得到的结果为dTYeoN8WdOfW4PiwgEdLa0gWFzo=,做完 urlencode 最终得到的签名 sig 为dTYeoN8WdOfW4PiwgEdLa0gWFzo%3d

  1. 将上一步得到的签名 sig 附在第一步构造的参数字符串后,作为请求的一个参数发送

上述例子里,请求参数即为ts=1443079775&ttl=300&uid=your_public_key&sig=dTYeoN8WdOfW4PiwgEdLa0gWFzo%3d

按照上面的说明,不难写出以下代码。

 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
// 1. 导入 moment 库
const moment = require("moment")
// 2. 获取集合变量中的公钥与私钥
const publicKey = pm.collectionVariables.get("PUBLIC_KEY")   // 在心知天气注册应用后即可获取
const privateKey = pm.collectionVariables.get("PRIVATE_KEY") // 在心知天气注册应用后即可获取
// 3. 构造待签名的对象
// 3.1 获取当前时间戳
const t = moment().unix()
const unsignParams = [
    {key:"ts",value:""+t},
    {key:"ttl",value:""+300},
    {key:"uid",value:publicKey},
]
// 4. 构造待签名参数的字符串
let str = unsignParams
// 4.1 参数按 ASCII 升序重排序
  .sort((a, b) => a.key > b.key ? 1 : -1 )                              
// 4.2 按key=value[&..]的形式拼接字符串
  .reduce((acc, item) => acc + (item.key + "=" + item.value + "&" ), "")
str = str.slice(0,str.length-1) // 删掉字符串末尾的 '&'
// 5. 使用 CryptoJS 完成签名
// 5.1 使用 HmacSHA1 计算签名
const sign = CryptoJS.HmacSHA1(str,privateKey)
// 5.2 使用 Base64 对上一步得到的签名进行转换
const base64Sign = CryptoJS.enc.Base64.stringify(sign)
// 5.3 对上一步得到的签名进行 URI 编码转换
const base64SignAndEncodeURI = encodeURIComponent(base64Sign)
// 6. 在原有请求参数的基础上,额外添加以下参数
pm.request.url.query.members.add({key:"sig",value:base64SignAndEncodeURI})
pm.request.url.query.members.add({key:"ts",value:""+t})
pm.request.url.query.members.add({key:"ttl",value:""+300})
pm.request.url.query.members.add({key:"uid",value:publicKey})

将上面这段代码复制到 Postman 的 pre-request script 中,进行请求即可。

天气实况 https://api.seniverse.com/v3/weather/now.json?location=beijing&language=zh-Hans&unit=c

Postman-Script3

3.3.2 链式调用:一键点击,同时调用两个接口

简介

某些时候,我们需要在接口A的响应中获取到某项数据,再将其作为接口B的请求参数发起调用。如果在界面上操作的话,我们需要以下步骤

  1. 调用接口A,得到响应数据
  2. 从响应数据中找到特定数据,并将其复制到接口 B 的参数中

对于这种情况,我们可以利用 pm 内置的 sendRequest 函数来简化流程,具体操作如下。

实例

Postman 在执行前置脚本时,会等待脚本中的所有延时操作完成后再发起请求,即使在脚本中编写异步函数也无需担心。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 1. 获取集合变量中的公钥与私钥
const privateKey = pm.collectionVariables.get("PRIVATE_KEY")// 在心知天气注册应用后即可获取
// 2. 通过城市搜索接口获取城市名称
const cityId = "WX4FBXXFKE4F"
pm.sendRequest("https://api.seniverse.com/v3/location/search.json?key="+privateKey+"&q="+cityId,  (err, response) =>{
    // 3. 从城市搜索的响应报文中取出城市名称
    const locationName = response.json().results[0].name
    // 4. 修改 Query 中原有的 location 字段
    pm.request.url.query.members[0].update({key:"location",value:locationName})
    // 5. 在 Query 中新增 key 字段
    pm.request.url.query.members.add({key:"key",value:privateKey})
});

Postman-Script4

在控制台输出中可以看到,在执行本次请求前,Postman 先行调用了 城市搜索 接口,并对天气实况接口的请求参数进行了修改。

善用前置接口,可以为你的接口调试工作节省出宝贵的时间,让你安心地投入到其他工作中,快来试试吧~

3.4 后置脚本的使用场景

接下来我们来看看后置接口的用法,在这个章节中,我会向你演示两个典型的使用场景

  1. 接口响应数据的校验与测试
  2. 接口响应数据的可视化
3.4.1 对响应数据进行测试与校验

pm 对象内置了一个 test 函数用来进行编写单元测试,我们可以利用这个函数对响应内容进行快速的验证。具体使用方式如下。

 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
// 1. 验证响应码
pm.test("Status code is 200", () => {
    pm.expect(pm.response.code).to.eql(200);
});
// 2. 验证某项数据
pm.test("verify data", function () {
    const data = pm.response.json()
    pm.expect(data.results[0].location.name).to.eql("北京")
})
const schema = {
    type: "object",
    properties: {
        results: {
            type: "array", properties: {
                location: {
                    type: "object", properties: {
                        id: { type: "string" },
                        name: { type: "string" }
                        // ...
                    }
                },
                now: {
                    type: "object", properties: {
                        text: { type: "string" },
                        // ...
                    }
                }
            }
        },
    },
    required: ["results"],
    additionalProperties: false
}
// 3. 验证 json schema
pm.test("verify schema", () => {
    pm.response.to.have.jsonSchema(schema);
})

后置脚本需要放置在 Tests 标签下,如图所示。

Postman-Script5

在这个后置脚本中,有三个单元测试,分别进行了响应码的验证、关键数据的验证以及JSON Schema 的验证。你可以在右侧 Test Results 中看到每项单元测试的结果。

3.4.2 对响应数据进行遴选并可视化

有时候我们调试的接口中有非常庞大的数据量,此时可以使用 Postman 内置的可视化操作来快速遴选当前感兴趣的数据。

Visualizer

Postman 支持 handlebars 模版以及chartjs图表,你可以使用这两个库创作出任意极具表现力的可视化界面。

接下来,我将向你演示如何对 心知天气V3-实况天气接口 的数据进行可视化。

实例

 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
// 1. 编写可视化模版
const template = `
    <table bgcolor="#FFFFFF">
        <thead>
            <caption>天气实况</caption>
        </thead>
        <tr>
            <th>城市</th>
            <th>省市区</th>
            <th>天气状况</th>
            <th>气温/体感温度</th>
            <th>能见度(米)</th>
        </tr>
        {{#each results}}
            <tr>
                <td>{{location.name}}</td>
                <td>{{location.path}}</td>
                <td>{{now.text}}</td>
                <td style="color:blue">{{now.temperature}}℃/{{now.feels_like}}℃</td>
                <td>{{now.visibility}}</td>
            </tr>

        {{/each}}
    </table>
`
// 2. 使用响应内容填充可视化模版
pm.visualizer.set(template,pm.response.json())

将以上代码复制到实况天气接口的 Tests 标签栏,发起接口调用后,你会得到如下所示的可视化效果。

Postman-Script6

总结

在本篇文章中,我们讨论了以下内容,

  1. 路径参数的使用
  2. 变量的使用
  3. 脚本的使用

相信通过这些小技巧,可以帮你更高效地完成接口调试工作。

创作不易,如果这些技巧对你有帮助的话,欢迎点赞、收藏、评论、转发,以便我及时收到反馈并加快下篇文章的产出。

行文匆忙,若文中内容存在错误,也请不要吝啬你的批评,再次感谢你的阅读。