ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

开源API客户端Bruno:轻量、离线优先、Git友好的Postman替代方案

开源API客户端Bruno:轻量、离线优先、Git友好的Postman替代方案 1. 上手体验与核心亮点1.1 从 Postman 迁移过来的第一感受先说结论我用 Postman 做了三年多接口调试从 8.x 一路用到 12.x日常就是对着几十个接口来回测试。Postman 越来越重的体积大家心里都有数每次冷启动少说等个三五秒有时候赶上自动更新重启那种等待的烦躁感几乎成了肌肉记忆。后来在 GitHub 上刷到一个叫 Bruno 的开源项目口号直接就是“离线优先的 API 客户端”。我第一反应是不太信毕竟这年头“轻量”“极速”都成了营销话术。但看到一个关键数字安装包 10 MB 级别启动不到 1 秒这就有点意思了。我当天就下载装好把项目里最常用的十几个接口配置搬过去实测了一周。体验最直接的三个点启动真的快。双击图标到界面完全可交互体感在 1 秒以内基本是秒开完全没有 Postman 那种转圈等待。存数据不需要登录。Bruno 的集合不是存在云端而是直接以文本文件形式保存在你本地指定的文件夹里天然离线可用连账号注册这步都省了。集合跟着 Git 走。每个请求文件都是纯文本格式可以直接放进 Git 仓库团队里谁改了接口、改了什么参数看 diff 一目了然。这三个点组合在一起解决的其实是很多开发者面对 Postman 时没说出口的痛点账号体系太繁琐、团队协作数据不透明、启动越来越慢、免费版功能还不断被切分。Bruno 用一套更简单、更符合程序员直觉的方式把这些事一次性处理掉了。1.2 适合什么样的人换过来先说结论不是所有人都适合立刻换。如果你是纯重度用户体验派依赖 Postman 的云端分享、团队工作空间、各种丰富的插件生态和界面动画效果那 Bruno 目前的形态可能偏朴素。但如果你是以下这几类人Bruno 值得认真试试后端开发者每天面对大量测试接口变更需要快速改 Header、改 Body、重新发送对启动速度和响应速度敏感。前端开发者想看清楚请求细节、抓接口返回做联调又不想被 Electron 系工具的沉重感拖累。团队协作场景项目仓库里直接带上接口集合新人克隆项目后打开 Bruno 就能看到全部接口不需要花钱买协作版也不需要额外同步步骤。习惯用 Git 管理一切的技术人接口定义和数据环境本身就是代码的一部分天然适合走代码评审流程。注重隐私和数据安全的场景所有数据留在本地不经过第三方服务器适合内网开发或对数据出域有要求的项目。我的判断是Bruno 的目标用户本来就是“认为接口定义应该和代码走同一套版本管理”的那批人。它的设计哲学是替开发者省掉那些和后端能力无关的流程负担把精力留在改接口本身这件事上。2. 核心细节解析为什么它敢说自己“轻”且“快”2.1 技术底子和启动速度的真相先说一个容易误导人的点10 MB 的安装包和“启动不到 1 秒”这两个宣传点放在一起容易让人误以为它是用 C 或 Rust 写的原生命令行工具。实际上 Bruno 用的是 Electron 框架底层是 Chromium 加 Node.js本质上还是个“内置浏览器”的桌面应用。那它为什么还能启动这么快关键在于两点第一安装包体积控制Electron 应用把运行体积压到 10 MB 级别确实少见说明作者对打包依赖做了非常克制的裁剪。界面没有塞动画库、没有重型 UI 框架渲染层很干净。第二启动逻辑极简没有开机自检、没有自动更新检测、没有运行时的数据同步等待打开应用只是加载本地文件索引不需要跟服务器握手。没有多余的远程依赖启动自然快。这和 Postman 形成了鲜明对比。Postman 虽然是老牌工具功能覆盖面广但多年来积累的功能模块、插件机制、账号体系、云端同步服务导致它每次启动都要加载大量模块等待时间越来越长。从纯工具理性角度看Bruno 是“只做一件事做精做透”的代表。我这个观点可能有争议但在日常接口调试场景下工具的开箱速度和流畅程度比多几个不常用的高级功能重要得多。高频操作的收益是实打实的。2.2 数据的存储逻辑和 Git 友好设计Bruno 的集合目录结构是这样的collection-name/ ├── bruno.json ├── environments/ │ ├── local.bru │ └── prod.bru └── requests/ ├── login.bru ├── get-user-info.bru └── update-password.bru每个.bru文件的内部结构是可读的文本格式类似 Markdown 搭配键值对。比如一个简单的 GET 请求长这样meta { name: Get User Info type: http seq: 2 } get { url: http://localhost:3000/api/users/{{userId}} body: none auth: none } headers { Accept: application/json X-Request-Id: {{$uuid}} }这套设计理念和 Postman 完全不同。Postman 的集合数据是一个 JSON 文件里面所有请求嵌套在一棵大 JSON 树里人直接看根本摸不清谁是谁diff 时只能看到整坨 JSON 变化。Bruno 则把一个集合切碎成一个个独立的文本文件改哪个请求就改哪个文件diff 结果准确到单行。实际操作中用 Git 管理接口集合的体验很像在管理一份代码目录。团队里有人改了登录接口的请求参数提交的 MR 里能清清楚楚看到- Authorization: Bearer {{oldToken}} Authorization: Bearer {{newToken}}这个特性对技术团队的诱惑力极其致命。你把接口测试的资料从“工具里的私有数据”变成了“仓库里的公开资产”接口的演进历史、修改理由、操作人全部沉淀在 Git 历史里。2.3 为什么“离线优先”反而是加分项Bruno 的“离线优先”不是说不能联网而是指它的核心能力不依赖任何云端服务。你用 Postman 时如果不登录账号就提示功能受限数据要强制绑定账号才能跨设备同步。Bruno 把账号体系整个砍掉数据和配置只存在你指定的目录团队同步靠 Git跨设备同步靠克隆仓库。从原理上看这是把接口调试工具从“SaaS 服务”拉回到了“单机软件”的定位。但在这个数据敏感度越来越高的时代本地优先反而成了优势。我所在的项目组有阵子涉及内部系统的对接接口信息本身就有一定敏感性拿 Postman 调试总得考虑数据是不是经过了别人的服务器。换成 Bruno 后这个顾虑直接消失因为所有数据从物理位置上就没有离开过你的电脑。当然这也带来了一个必须接受的代价——没有云备份。数据安全需要你自己负责比如定期提交 Git、养成及时 push 的习惯。这个取舍我认为非常划算毕竟接口数据同步 Git 本身就是团队开发流程的一部分云同步反而多出一步人工操作。3. 实操过程与核心配置指南3.1 从下载到创建第一个接口请求的完整流程安装 Bruno 的路径不多但都比较直接。我主要推荐两种方式官网下载安装包Bruno 官网根据系统版本直接下载支持 Windows、macOS、Linux 三端。Linux 用户还能选.deb、.rpm或 AppImage 格式。命令行安装软件包管理器macOS 用户可以直接用brew install brunohq/tap/brunoWindows 用户可以用winget install Bruno.BrunoLinux 上依发行版不同也可以用对应的包管理器安装。安装完成后首次打开是空白的集合界面这时候不要急着点“创建”先建一个项目文件夹把接口数据存在一个专门目录里。像这样规划project-api/ ├── api-tests/ // 存放 Bruno 集合 └── docs/ // 可选放接口说明文档接下来正式创建集合。在 Bruno 主界面点击“New Collection”给它起个名字然后选择存放目录。我建议直接把目录选在项目仓库根目录下这样待会儿 Git 提交时就能一起带上去。创建完集合后在里面新建第一个请求。这时会看到界面右边有个编辑器左侧是请求方法选择默认是 GET还有 URL 输入框、Headers、Params、Body、Auth 等 Tab。整个过程和 Postman 的操作习惯保持了一致从 Postman 迁移过来的学习成本很低熟练的人可能五分钟内就能完成首次配置。第一个接口用最简单的登录接口为例post { url: http://localhost:8080/api/auth/login body: json auth: none } body:json { { username: {{adminUser}}, password: {{adminPassword}} } }保存完这个请求你会看到requests目录下生成了一个login.bru文件用编辑器打开就能看到类似上面的纯文本格式。3.2 环境变量与多环境切换的配置方法刚开始用 Bruno 时最容易忽略的就是环境变量功能后面接口多了才发现这步省不掉。Bruno 的环境变量设计思路和 Postman 不太一样。Postman 把环境变量做成“一组一组的全局选择”Bruno 则是在集合目录下专门创建一个environments文件夹里面每个.bru文件对应一组环境。举例来说environments/ ├── local.bru ├── dev.bru └── prod.bru每个环境文件的内容也很简单vars { host: http://localhost:8080 adminUser: test_admin adminPassword: 123456 token: }然后在请求文件里通过{{host}}、{{adminUser}}这样的双花括号语法引用变量。发送请求前在界面右上角的下拉菜单切换对应的环境文件Bruno 会动态替换变量值。需要注意的一个坑环境文件里不要提交真实密码或 token 到 Git。建议把prod.bru里的敏感字段留空在本地手动补全然后通过.gitignore忽略一些关键环境文件或者只在本地创建local.bru。Bruno 还内置了一些动态变量在请求拼接时很常用。比如{{$uuid}}生成随机 UUID。{{$isoTimestamp}}生成当前 ISO 格式时间戳。{{$randomInt}}生成随机整数。{{$envVarName}}读取当前环境变量。这些变量能直接用在 URL、Header、Body 里类似 Postman 的预定义变量不需要额外写脚本简单又实用。3.3 测试脚本与数据提取接口调试不可能只做手动发送、肉眼检查返回结果测试脚本是刚需。Bruno 的脚本体系跟 Postman 类似分成两部分请求前脚本Script发送请求前执行常用于设置签名、生成时间戳、动态计算参数。请求后脚本Tests/Assertions收到响应后执行用于断言状态码、提取返回数据赋给环境变量。两者在界面上的入口分别是 Pre-Request 和 Tests 两个 Tab都用 JavaScript 编写引擎基于 Node.js。最常用的请求后脚本比如断言状态码const res bru.getRes(); bru.assert(res.status 200, Expected 200 OK);提取登录返回的 token 并写入环境变量const res bru.getRes(); const data res.body; if (data data.token) { bru.setEnvVar(token, data.token); bru.log(Token saved: data.token); }这两段脚本覆盖了绝大部分接口联动场景先登录拿 token再把 token 作为后续接口的 Authorization 头。Postman 里的pm.response.to.have.status(200)写法在 Bruno 里是bru.assert(条件, 描述)语法逻辑一致但略有不同迁过来时需要顺手改一下。请求前脚本可以用来处理签名参数。举个例子有个接口需要的签名值是当前时间戳加盐后的 MD5那就在 Pre-Request 里写const Md5 require(md5); const timestamp Date.now(); const salt my-secret-salt; const sign Md5(timestamp salt); bru.setVar(timestamp, timestamp.toString()); bru.setVar(sign, sign);然后请求体的 URL 参数里直接用{{timestamp}}和{{sign}}。Bruno 会自动按顺序执行请求前脚本、发起请求、执行请求后脚本整个流程和 Postman 的 Interceptor 机制是同一路由子。3.4 使用命令行工具做接口回归测试Bruno 除了图形界面外还提供了一套命令行的 CLI 工具这是很多 Postman 免费用户羡慕已久的能力。把接口集合变成自动化测试集不需要额外写测试框架直接命令行跑安装 Bruno CLInpm install -g usebruno/cli在集合目录下运行测试bru run . --env local命令行工具会按照集合里每个请求文件的顺序依次执行执行完输出每个接口的状态码、耗时、断言结果。也可以指定只跑某个文件夹bru run requests/login.bru --env local还有个实用的参数--reporter-html能生成一份 HTML 格式的测试报告bru run . --env dev --reporter-html --output ./reports这个功能最大的价值是可以接入 CI。在 GitLab CI 或 GitHub Actions 里拉完代码后自动跑一轮接口测试接口挂了就直接拦截合并请求测试结果作为构建产物留存。这比起在 Postman 里单独建 Collection 再通过 Newman 执行流程上更顺滑因为数据源和代码在同一个仓库天然不需要额外导出动作。4. 常见问题与避坑指南4.1 中文乱码和接口请求头编码问题国内开发者最常遇到的就是接口返回 JSON 里的中文乱码。这个问题和 Bruno 本身关系不大大多是请求时没有声明正确的请求编码或者服务端没有正确返回 Content-Type。排查思路如下检查请求头是否设置了Accept: */*或Accept: application/json确保服务端知道客户端期望 JSON 格式。如果接口返回的非 JSON 内容是 HTML 乱码可能是服务端返回了text/html编码格式需要在脚本里手动解码。检查环境变量里的值是否包含中文如果值是从其他文件粘贴过来的确认源文件保存的编码是 UTF-8不要用 GBK。实际踩坑最多的场景是在 Windows 上用记事本新建环境文件默认可能保存为 ANSI 编码Bruno 按 UTF-8 读取时中文字符就乱码了。解决方式是用 VS Code 等编辑器重新保存为 UTF-8 编码。如果接口本身传参就需要 GBK 编码Bruno 并没有直接在界面上提供编码转换选项这种场景我建议在请求前脚本里用 JavaScript 做手动编码转换。虽然麻烦但这类接口在正规系统里越来越少见了。4.2 登录态依赖怎么串联多接口测试时最常见的问题是登录后拿到的 token怎么自动传给后续每个接口Bruno 的变量作用域需要理解清楚。用bru.setVar()设置的变量是当前请求级别用bru.setEnvVar()设置的是环境级别在当前环境文件内全局生效。后续接口只要引用{{token}}Bruno 就会从环境文件绑定的变量集合里查找值。推荐的做法是单独建一个auth-login.bru请求文件专门用来执行登录操作。然后在后续所有需要 token 的请求文件里Auth 类型选择 Bearer TokenToken 值填{{token}}。有个细节容易忽略切换环境后之前通过setEnvVar写入的变量是动态写入内存的不会自动保存到.bru环境文件里。你要是重启了 Bruno 工具再切一次环境token 变量可能就丢了。解决办法是把 token 初始值在环境文件里留一个过期占位符然后在请求前脚本里加一个判断如果 token 为空才执行登录请求。这样保证每次运行测试集都能自动完成登录、后续接口自动携带最新 token而不是手动画刷新 token。4.3 自动化测试时的执行顺序问题Bruno 默认按照请求文件名的字母顺序执行测试集而不是按照你在界面上拖拽的顺序。这在跑多个请求相互依赖的测试链时非常容易出错。举个例子你有login.bru和get-user.bru如果登录接口的名称起成api-login.bru按字母排序它会排在get-user.bru前面执行顺序没问题。但如果起名是login.bru它排在后面那 get-user 先跑时 token 还没初始化断言必然挂。解决办法有两种第一种是文件名用序号前缀比如01-login.bru、02-get-user.bru、03-update-password.bru这是最暴力也最直观的方法。 第二种是在bruno.json里显式配置执行顺序或者在请求文件里通过seq字段设置序号meta { name: Login type: http seq: 1 }seq数值越小越先执行。我实测下来自己项目中用的是混合方案核心链路接口用序号前缀其余零散请求不强制排序保持文件夹的自然组织。4.4 和 Postman 的兼容性以及数据迁移问题从 Postman 迁过来的时候最担心的是历史数据怎么搬。Bruno 在较新版本里原生支持导入 Postman Collectionv2.1 标准格式。路径是主界面右上角菜单选择 Import然后选择 Postman Collection 的 JSON 文件即可。导入后有两个常见情况需要注意。第一Postman 里用{{variable}}的地方Bruno 基本能正确映射到环境变量但部分 Postman 特殊的脚本变量比如pm.collectionVariables不会自动转换需要手动在脚本里改成bru.getEnvVar或bru.setEnvVar。第二Postman 里的断言脚本写在 Tests 标签页导入时 Bruno 会尝试转换但pm.test的语法不会自动变成bru.assert需要手动改。我自己当时迁移时总共搬了二十多个接口文件机械性的部分一首歌的时间就完成了真正花时间的是逐个检查脚本里的 API 调用差异特别是签名逻辑和 token 提取逻辑。另外提一句Bruno 完全支持从 OpenAPI/Swagger 文件导入集合。如果你手头有最新的 OpenAPI 文档直接用这个方式重新生成集合比从 Postman 搬更干净。4.5 插件生态还不完善时的替代方案对习惯了 Postman 各种 Marketplace 插件的人来说Bruno 目前的插件生态显得比较朴素官方主要以内置能力为主。好在开发者可以在脚本里引用 npm 包等于保留了一个口子。举个例子接口测试里需要用到加密算法Postman 生态里可以搜到现成的库。Bruno 的解决办法是直接引入 npm 包const CryptoJS require(crypto-js); const hash CryptoJS.HmacSHA256(message, secret); const hexHash CryptoJS.enc.Hex.stringify(hash); bru.setVar(sign, hexHash);前提是脚本运行时环境支持 require实测 Bruno 的脚本引擎是支持 CommonJS 模块引用的。不过要注意安装第三方依赖需要修改集合目录下的package.json或者在集合目录里执行npm install然后 Bruno 会从node_modules里解析依赖。还有一个容易踩的坑在写脚本require(path)、require(fs)访问本机文件系统时Bruno 出于安全考虑做了限制部分 Node.js 内置模块不可用。如果需要在脚本里读写文件做数据准备建议改用bru.getFile方法来读取文件内容。具体的 API 细节以官方文档为准版本间可能有差异。5. 写到最后的一点实际建议Bruno 目前在接口调试工具里算是一股清流。它不追求大而全而是把接口集合的管理方式拉回到了开发者最喜欢的“文本文件 Git 命令行”时代用最朴素的方式解决了 Postman 在统一协作上积累的复杂度问题。改用 Bruno 后我最大的感受其实是“心理负担变小了”。之前调接口打开 Postman 意味着打开一个要等待启动的重量级应用还要面对时不时弹出的更新提示。现在打开 Bruno像打开一个文本编辑器一样轻松数据就在本地文件夹里改接口测试用例就像改代码一样自然。如果你还在犹豫要不要从 Postman 迁过来我的建议是从一个小项目开始试水。用 Bruno 跑一遍你的核心接口链路感受一下启动速度和 Git 管理机制再决定要不要全量迁移。工具这东西最终还是要服务于人用得顺手、省心提效就是好工具。Bruno 在这一点上确实做到了 Postman 很长时间都没有做到的事。
返回列表