ApiPost 中配置自动获取 Token 并调用业务接口完整指南
一、目标
在 ApiPost 中实现:每次发送业务请求时,自动判断 Token 是否过期,过期则自动调用认证接口获取新 Token,无需手动操作。
二、整体流程
点击"发送"业务请求
↓
全局预执行脚本自动运行
↓
检查环境变量中 token 是否存在且未过期
↓
过期/为空 → 自动调用认证接口 → 解析响应 → 存入环境变量
未过期 → 跳过,使用缓存 token
↓
全局 Header 自动拼装 Authorization: Bearer {{token}}
↓
业务请求正常发送
注:
博客:
https://blog.csdn.net/badao_liumang_qizhi
三、配置步骤
3.1 配置环境变量
位置: 右上角「环境管理」→ 新建/选择环境
添加以下变量(初始值留空):
| 变量名 | 初始值 | 说明 |
|---|---|---|
base_url |
http://127.0.0.1:8080 |
本地服务地址 |
token |
(空) | 脚本自动填充 |
token_time |
(空) | 记录获取时间,用于过期判断 |
3.2 配置全局请求头
位置: 全局参数 → Header 标签页
添加一条:
| 参数名 | 参数值 |
|---|---|
Authorization |
Bearer {``{token}} |
{``{token}}是环境变量的引用语法,ApiPost 会在发送时自动替换为实际值。
3.3 配置全局预执行脚本
位置: 全局参数 → 预执行脚本(Pre-request Script)标签页
四、预执行脚本(通用模板)
4.1 OAuth2 Password Grant 模式
适用于通过 OAuth2 认证服务获取 Token 的场景。
javascript
// ===== 配置区域(替换为你的实际值)=====
var AUTH_URL = "https://your-auth-server.com/oauth/token";
var CLIENT_ID = "your_client_id";
var CLIENT_PASSWORD = "your_client_password";
var USERNAME = "your_username";
var PASSWORD = "your_password";
var TOKEN_EXPIRE_MS = 14400000; // token 有效期(毫秒),此处为 4 小时
// ===== 配置区域结束 =====
let token = apt.variables.get("token");
let tokenTime = apt.variables.get("token_time");
let now = Date.now();
// 判断 token 是否存在且未过期
if (!token || !tokenTime || (now - Number(tokenTime)) > TOKEN_EXPIRE_MS) {
let base64 = btoa(CLIENT_ID + ":" + CLIENT_PASSWORD);
apt.sendRequest({
url: AUTH_URL,
method: "POST",
header: {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Basic " + base64
},
body: {
mode: "urlencoded",
urlencoded: [
{ key: "grant_type", value: "password" },
{ key: "username", value: USERNAME },
{ key: "password", value: PASSWORD }
]
}
}, function(err, res) {
if (err) {
console.log("获取token失败: " + err);
return;
}
// 兼容多种响应格式解析
let data;
try {
if (res.json && typeof res.json === 'function') {
data = res.json();
} else if (res.body) {
data = JSON.parse(res.body);
} else if (res.text && typeof res.text === 'function') {
data = JSON.parse(res.text());
} else if (typeof res === 'string') {
data = JSON.parse(res);
} else {
data = res;
}
} catch(e) {
console.log("解析响应失败: " + e.message);
console.log("原始响应: " + String(res));
return;
}
if (data && data.access_token) {
apt.variables.set("token", data.access_token);
apt.variables.set("token_time", String(Date.now()));
console.log("Token已自动刷新");
} else {
console.log("响应中没有access_token: " + JSON.stringify(data).substring(0, 200));
}
});
}
4.2 普通登录接口模式
适用于通过常规登录接口(POST JSON body)获取 Token 的场景。
javascript
// ===== 配置区域 =====
var LOGIN_URL = "https://your-server.com/api/login";
var LOGIN_BODY = {
username: "your_username",
password: "your_password"
};
// token 在响应中的路径,如 data.token 或 data.access_token
var TOKEN_FIELD = "data.token";
var TOKEN_EXPIRE_MS = 7200000; // 2 小时
// ===== 配置区域结束 =====
let token = apt.variables.get("token");
let tokenTime = apt.variables.get("token_time");
let now = Date.now();
if (!token || !tokenTime || (now - Number(tokenTime)) > TOKEN_EXPIRE_MS) {
apt.sendRequest({
url: LOGIN_URL,
method: "POST",
header: {
"Content-Type": "application/json"
},
body: {
mode: "raw",
raw: JSON.stringify(LOGIN_BODY)
}
}, function(err, res) {
if (err) {
console.log("登录失败: " + err);
return;
}
let data;
try {
if (res.json && typeof res.json === 'function') {
data = res.json();
} else if (res.body) {
data = JSON.parse(res.body);
} else if (typeof res === 'string') {
data = JSON.parse(res);
} else {
data = res;
}
} catch(e) {
console.log("解析失败: " + e.message);
return;
}
// 按路径提取 token(支持 data.token 这种嵌套路径)
let tokenValue = TOKEN_FIELD.split('.').reduce(function(obj, key) {
return obj ? obj[key] : null;
}, data);
if (tokenValue) {
apt.variables.set("token", tokenValue);
apt.variables.set("token_time", String(Date.now()));
console.log("Token已自动刷新");
} else {
console.log("找不到token字段: " + JSON.stringify(data).substring(0, 200));
}
});
}
4.3 从 Set-Cookie 中提取 Token
适用于登录后 Token 放在响应头 Cookie 中的场景。
javascript
// ===== 配置区域 =====
var LOGIN_URL = "https://your-server.com/login";
var LOGIN_BODY = {
username: "your_username",
password: "your_password"
};
var COOKIE_NAME = "your_jwt_cookie_name"; // 如 coc_jwt、session_token 等
var TOKEN_EXPIRE_MS = 7200000;
// ===== 配置区域结束 =====
let token = apt.variables.get("token");
let tokenTime = apt.variables.get("token_time");
let now = Date.now();
if (!token || !tokenTime || (now - Number(tokenTime)) > TOKEN_EXPIRE_MS) {
apt.sendRequest({
url: LOGIN_URL,
method: "POST",
header: {
"Content-Type": "application/json"
},
body: {
mode: "raw",
raw: JSON.stringify(LOGIN_BODY)
}
}, function(err, res) {
if (err) {
console.log("登录失败: " + err);
return;
}
// 从响应头中提取 Set-Cookie
let cookies = "";
if (res.headers) {
// headers 可能是数组或对象
if (Array.isArray(res.headers)) {
res.headers.forEach(function(h) {
if (h.key && h.key.toLowerCase() === 'set-cookie') {
cookies += h.value + ";";
}
});
} else if (res.headers['set-cookie']) {
cookies = res.headers['set-cookie'];
} else if (res.headers['Set-Cookie']) {
cookies = res.headers['Set-Cookie'];
}
}
// 正则提取指定 cookie 的值
let regex = new RegExp(COOKIE_NAME + "=([^;]+)");
let match = cookies.match(regex);
if (match && match[1]) {
apt.variables.set("token", match[1]);
apt.variables.set("token_time", String(Date.now()));
console.log("Token已从Cookie中提取并刷新");
} else {
console.log("Cookie中未找到" + COOKIE_NAME);
console.log("实际Cookie: " + cookies.substring(0, 200));
}
});
}
五、脚本关键 API 说明
5.1 全局对象兼容性
| ApiPost 版本 | 全局对象 | 说明 |
|---|---|---|
| ApiPost 7+ | apt |
新版本推荐使用 |
| ApiPost 旧版 | pm |
兼容 Postman 风格 |
如果
apt报错就换pm,反之亦然。
5.2 核心 API
| API | 作用 |
|---|---|
apt.variables.get("key") |
获取环境变量 |
apt.variables.set("key", "value") |
设置环境变量 |
apt.sendRequest(options, callback) |
在脚本中发送 HTTP 请求 |
btoa(string) |
Base64 编码(用于 Basic Auth) |
console.log(msg) |
控制台输出调试信息 |
5.3 sendRequest 参数结构
javascript
apt.sendRequest({
url: "完整URL",
method: "POST", // GET / POST / PUT / DELETE
header: { // 请求头(对象格式)
"Content-Type": "application/json",
"Authorization": "Basic xxx"
},
body: {
mode: "urlencoded", // urlencoded | raw | formdata
urlencoded: [ // mode 为 urlencoded 时
{ key: "name", value: "value" }
],
raw: '{"key":"val"}' // mode 为 raw 时
}
}, function(err, res) {
// err: 错误信息,成功时为 null
// res: 响应对象
});
5.4 响应解析兼容写法
由于不同版本 res 的结构不同,推荐使用兼容写法:
javascript
let data;
try {
if (res.json && typeof res.json === 'function') {
data = res.json(); // 方式1: res.json()
} else if (res.body) {
data = JSON.parse(res.body); // 方式2: res.body 是字符串
} else if (res.text && typeof res.text === 'function') {
data = JSON.parse(res.text()); // 方式3: res.text()
} else if (typeof res === 'string') {
data = JSON.parse(res); // 方式4: res 直接是字符串
} else {
data = res; // 方式5: res 本身就是对象
}
} catch(e) {
console.log("解析失败: " + e.message);
}
六、调试技巧
6.1 查看脚本控制台输出
发送请求后,在 ApiPost 底部找到 控制台(Console) 面板,查看 console.log 的输出。
6.2 调试响应结构
如果不确定 res 的实际结构,先加上:
javascript
console.log("响应类型: " + typeof res);
console.log("响应内容: " + JSON.stringify(res).substring(0, 300));
根据打印结果确定正确的解析方式。
6.3 强制刷新 Token
手动清空环境变量中的 token 值,下次发送请求时脚本会重新获取。
七、业务接口配置示例
配置好全局脚本和 Header 后,新建业务接口只需关注业务本身:
- URL :
{``{base_url}}/api/your-endpoint - Method:POST
- Body(raw JSON):
json
{
"pageNum": 1,
"pageSize": 10
}
不需要手动填写 Authorization,全局配置会自动处理。
八、常见问题
| 问题 | 原因 | 解决 |
|---|---|---|
Unexpected token u in JSON at position 0 |
res 是 undefined 或解析方式不对 |
用兼容写法逐个尝试,先打印 typeof res |
apt is not defined |
版本不支持 apt | 换成 pm |
btoa is not defined |
环境不支持 btoa | 用 Buffer.from(str).toString('base64') 替代 |
| Token 获取成功但接口仍 401 | Header 没生效 | 检查全局 Header 是否写了 Bearer {``{token}}(注意空格) |
| 每次都重新获取 Token | token_time 变量没设置上 |
检查变量名拼写,确认 apt.variables.set 可用 |
| 认证接口返回 401 | client_id 或密码错误 | 单独新建一个接口手动测试认证地址是否可达 |
九、方案对比
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 全局预执行脚本 | 全自动,一次配置永久生效 | 需要版本支持 sendRequest | 日常开发首选 |
| 单独 Token 接口 + 后执行脚本 | 所有版本都支持 | 过期后需手动点一次 | 版本不支持 sendRequest |
| bat 脚本复制到剪贴板 | 零配置 | 每次手动操作 | 临时使用 |