Skip to content

用 Bruno 联调

Bruno 是什么

Bruno 是一个开源的 API 客户端,作用和 Postman、Insomnia 类似:管理请求、切换环境、 发请求看响应。区别在于两点,正好是我们把它选成联调工具的原因:

  • 请求以纯文本文件存盘.bru),一个接口一个文件,可以直接进 Git、能 diff、能 review。
  • 不需要登录账号,也不把你的集合同步到云端 —— 税务数据这类场景,凭据和请求 不出本机是硬要求。

下面是装好我们的接口包之后的样子:左边是按业务分好组的 17 个接口, 右边是集合自带的说明文档。

Bruno 装载「税务发票数据开放平台」接口包后的主界面
Bruno 装载「税务发票数据开放平台」接口包后的主界面

和文档站的分工

文档站回答"这个字段是什么意思、边界在哪",Bruno 回答"我现在能不能打通"。 两边的接口定义出自同一份 openapi.yaml,不会各说各话。

下载 Bruno

免安装 / 免注册,下载解压即可用。

本次构建未包含桌面端安装包,请到 Bruno 官网 下载,或联系平台获取。

这是第三方软件

Bruno 由 Bruno 团队开发,平台只是转发官方发行包,未作任何修改。 你也可以直接从 Bruno 官网 下载, 版本不限,接口包对版本没有要求。

导入接口包

接口包就是那 17 个接口的定义,由平台的 openapi.yaml 生成。 两种拿法,按你的情况选一种就行。

默认版:自己配置

拿通用包,导入后自己填环境变量。适合要把包提交进自己仓库、 或者多人共用一份定义的场景。

默认版接口包平台提供

17 个接口 + 2 套环境骨架,V2 接口自动签名。环境变量全部留空,导入后自己填。

下载 tax-rpa-bruno-collection.zip 20 KB

SHA-256 5cf6ee4b607cf3e07b6e289c514bea8f5241c0f88a520fbf6bbb64fb6430aa40

解压后在左侧 Collections 面板点 ⋮ 选 Open collection, 选中解压出来的 税务发票数据开放平台 目录:

Collections → Open collection
Collections → Open collection

是 Open 不是 Import

Open collection 直接打开磁盘上的目录,改动落回文件、可以进版本库。 Import collection 是给 Postman 等外部格式用的,这里不要选。

右上角切换 测试环境 / 生产环境

右上角环境切换
右上角环境切换

点环境名进变量表,把下面几项填上。 Variables 页签是普通变量,Secrets 页签是密钥:

Variables 与 Secrets 分开管理
Variables 与 Secrets 分开管理
变量填什么在哪个页签
channelCode渠道编码,如 BANKVariables
externalOrderId你的业务订单号Variables
orderNo订单查询返回的 job_idVariables
channelKey渠道 API KeySecrets
callbackSecretCallback Secret,签名用Secrets

secret 变量不落文件

Bruno 把 Secrets 页签里的值存在本机,不写进 .bru 文件。 所以默认版接口包可以安全地提交进你自己的 Git 仓库。

定制版:填表生成,导入即用

在下面填好你自己的参数,浏览器当场打包 —— 解压导入后环境已经配好, 不用再手工填一遍。

默认不写。两项会作为 Bruno 的 secret 变量留空,导入后在 Bruno 里填, 存本机不进文件 —— 这样生成的包可以安全地传给同事或提交进 Git。

正在载入集合模板…

生成过程全在本地

zip 是在你的浏览器里用集合模板拼出来的,参数和密钥不会上传到任何地方。

导入方式和默认版一样:Open collection 选中解压出来的目录。区别只是 环境变量已经预填好,如果没勾选"把密钥写进包里",就只剩 channelKeycallbackSecret 两项要在 Secrets 页签补上。

签名是自动的

V2 那三个发票交付接口强制签名,/api/channel/data/* 在渠道启用强制签名时也要签。 集合级的 pre-request 脚本会自动处理,你不需要手工算 HMAC:

js
// collection.bru(节选)
const canonical = [timestamp, nonce, method, url.pathname, rawQuery, bodyHash].join('\n');
const signature = CryptoJS.HmacSHA256(canonical, secret).toString(CryptoJS.enc.Hex);
req.setHeader('X-Channel-Timestamp', timestamp);
req.setHeader('X-Channel-Nonce', nonce);
req.setHeader('X-Channel-Signature', 'sha256=' + signature);

几个实现上的取舍,出问题时值得知道:

  • 只对规范里声明了签名的接口签名,路径匹配表由生成脚本从 openapi.yaml 推导, 不是硬编码。
  • 强制签名的接口(V2)没填 callbackSecret 会直接抛错,而不是发出去等 401。
  • 可选签名的接口/api/channel/data/*)只在填了密钥时才签 —— 渠道处于 OPTIONAL 模式时只带 Key 也能调,不强迫你配密钥。
  • 脚本会先固定 body 文本再算哈希,避免 Bruno 重新序列化后字节不一致、服务端签名校验不通过。

算法细节见鉴权与签名

典型顺序

mermaid
flowchart LR
  A[创建授权链接] --> B[浏览器打开 authorization_url]
  B --> C[查询订单<br/>拿 job_id]
  C --> D[填进 orderNo]
  D --> E[查询产品状态]
  E --> F[取数 / 下载报告]
  1. 授权与订单 → 创建授权链接,把响应里的 authorization_url 复制到浏览器完成授权。
  2. 查询订单,等 state 变成 SUCCESS,把 job_id 填进环境变量 orderNo
  3. 查询税务/发票产品状态,确认 state=SUCCEEDEDavailable=true
  4. 按需调 税务数据 / 发票数据 / 报告 下的接口。

进 CI

Bruno 有命令行版,可以把联调集合直接当回归用例跑:

bash
npm i -g @usebruno/cli
bash
bru run --env 测试环境 --env-var channelKey=$RPA_CHANNEL_KEY --env-var callbackSecret=$RPA_CALLBACK_SECRET

凭据从 CI 的 secret 注入,不写进任何文件。

什么时候用文档站,什么时候用 Bruno

你要做的事去哪
查字段含义、取值范围、边界接口参考数据说明
看一眼某个接口返回长什么样接口参考页的 Test Request
正式联调、切生产、跑回归Bruno

为什么在线调用不推荐用于生产

浏览器发起的请求受同源策略约束,要求目标环境把文档站的源加进 RPA_CORS_ORIGINS; 而且要把渠道 Key 敲进网页。测试环境用它很方便,生产环境建议只走 Bruno。

适配平台 1.5.3 · 接入指南、接口参考、字段字典与税局状态统一入口。