使用JavaScript在Apifox中编写自定义Mock脚本是应对复杂模拟场景的解决方案。能让你获取请求信息、执行动态逻辑,并返回高度定制化的响应,从而模拟出几乎任何真实的API行为。
一、 Mock原理和启用方法
自定义Mock脚本的原理是:获取请求 -> 处理逻辑 -> 动态设置响应。执行优先级低于“高级Mock”中的“期望”,但高于所有静态Mock规则。
启用方法:在接口的“高级 Mock”设置中,切换到“自定义脚本”标签页并开启此功能。
二、 API详解
脚本通过两个对象 fox.mockRequest 和 fox.mockResponse 和Apifox交互。最主要的API:
fox.mockRequest:用于获取入站请求的所有信息。
.getParam(key):获取请求参数,自动从路径(Path)、查询参数(Query)、请求体(Body) 中查找。
.headers:获取请求头对象(如 fox.mockRequest.headers.get('token'))。
.cookies:获取请求Cookie对象。
fox.mockResponse:用于控制出站响应的所有方面。
.json():获取由智能Mock或其他规则生成的初始JSON响应,作为修改的起点。
.setBody(body):设置最终的响应体,支持JSON对象或字符串。
.setCode(code):动态设置HTTP状态码(如404, 403)。
.setDelay(ms):设置响应延迟,模拟网络延迟或后端处理时间(单位:毫秒)。
.headers:操作响应头(如 .add({'X-Token': 'xxx'}))。
三、 应用脚本实例
场景1:模拟带状态变更的流程(如订单)
模拟一个订单从创建、支付到发货的状态流转,并验证状态逻辑。
javascript
const orderId = fox.mockRequest.getParam('orderId');
const action = fox.mockRequest.getParam('action'); // 例如:query, pay, ship
let baseResponse = fox.mockResponse.json();
// 初始化一个模拟的“订单数据库”
const orderStore = {
'order-123': { id: 'order-123', status: 'created', paid: false, shipped: false }
};
let order = orderStore[orderId] || { id: orderId, status: 'not_found' };
if (action === 'pay' && order.status === 'created') {
order.status = 'paid';
order.paid = true;
baseResponse.message = '支付成功';
} else if (action === 'ship' && order.status === 'paid') {
order.status = 'shipped';
order.shipped = true;
baseResponse.message = '发货成功';
} else if (action === 'query') {
baseResponse.message = '查询成功';
} else {
// 状态流转错误
fox.mockResponse.setCode(400);
baseResponse.message = `非法操作: 当前状态[${order.status}]不能执行[${action}]`;
}
orderStore[orderId] = order;
baseResponse.data = order;
fox.mockResponse.setBody(baseResponse);
场景2:生成符合业务规则的动态数据
模拟返回一个分页列表,其中数据根据查询条件动态生成,并注入真实感数据。
javascript
// 引入Mock.js库生成更真实的数据
var MockJs = require('mockjs');
const page = parseInt(fox.mockRequest.getParam('page')) || 1;
const pageSize = parseInt(fox.mockRequest.getParam('pageSize')) || 10;
const keyword = fox.mockRequest.getParam('keyword');
// 计算总条数,模拟一个固定值
const total = 125;
// 计算本次返回的数据
const startIndex = (page - 1) * pageSize;
const data = [];
for (let i = 0; i < pageSize && startIndex + i < total; i++) {
let item = {
id: `id-${startIndex + i + 1}`,
// 使用Mock.js生成中文名、邮箱、城市
name: MockJs.mock('@cname'),
email: MockJs.mock('@email'),
city: MockJs.mock('@city'),
// 根据关键词模拟“搜索”
description: MockJs.mock('@csentence')
};
// 如果有关键词,则模拟匹配第一条数据
if (keyword && i === 0) {
item.name = `${keyword}(相关结果)`;
}
data.push(item);
}
fox.mockResponse.setBody({
code: 0,
message: 'success',
data: {
list: data,
pagination: {
page: page,
pageSize: pageSize,
total: total
}
}
});
// 模拟查询延迟
fox.mockResponse.setDelay(300);
场景3:模拟错误和认证逻辑
集中处理认证失败、参数校验错误、资源不存在等多种异常情况。
javascript
const token = fox.mockRequest.headers.get('Authorization');
const userId = fox.mockRequest.getParam('userId');
// 1. 认证检查
if (!token || token !== 'Bearer valid-token-123') {
fox.mockResponse.setCode(401);
fox.mockResponse.setBody({
code: 10001,
message: '无效或过期的访问令牌',
timestamp: new Date().toISOString()
});
return; // 关键:使用return终止脚本继续执行
}
// 2. 参数校验
if (!userId || userId.length < 5) {
fox.mockResponse.setCode(400);
fox.mockResponse.setBody({
code: 10002,
message: '参数错误: userId格式无效',
invalidField: 'userId'
});
return;
}
// 3. 业务逻辑检查 (模拟资源不存在)
const validUserIds = ['user-1001', 'user-1002'];
if (!validUserIds.includes(userId)) {
fox.mockResponse.setCode(404);
fox.mockResponse.setBody({
code: 20001,
message: `请求的用户ID ${userId} 不存在`
});
return;
}
// 4. 模拟成功响应
fox.mockResponse.setBody({
code: 0,
data: {
id: userId,
name: '张三',
role: 'admin'
}
});
四、 注意事项
脚本的独立性:Mock脚本不能使用环境变量、pm对象、以及前后置操作中的脚本语法。它是一个纯JavaScript环境,主要依赖fox对象。
性能和代码:对于极其复杂的逻辑,建议在脚本中仅保留调度代码,将主要算法封装在自定义的require模块中(如果Apifox环境支持)。避免单段脚本过长。
配合:“高级Mock”中的“期望”适用于条件简单、响应固定的场景(如参数id=1返回A,id=2返回B)。当逻辑需要计算、循环或访问外部库时,再使用自定义脚本。
调试技巧:目前Mock脚本内没有直接的console.log输出。调试主要依靠构造不同的请求参数,观察最终的响应体是否正确。建议先编写简单的脚本来验证 fox.mockRequest.getParam() 能正确获取到参数。