Guía de uso de la función de script de APICatcher
APICatcher tiene un motor de secuencias de comandos basado en JavaScript integrado, lo que le permite escribir secuencias de comandos personalizadas para interceptar y modificar solicitudes y respuestas HTTP/HTTPS. La función de secuencias de comandos es potente y flexible, adecuada para la depuración de desarrollo, pruebas de API, simulación de datos y otros escenarios.
Índice
- Inicio rápido
- Estructura básica del script
- Función de intercepción de solicitud interceptRequest
- Función de intercepción de respuesta interceptResponse
- API integrada
- Ejemplos prácticos
- Notas
Inicio rápido
- Abra APICatcher y vaya a la página de administración de "Scripts".
- Haga clic en "Agregar script", y el sistema completará automáticamente el código de plantilla.
- Establezca las Condiciones de coincidencia del script (como Host, Path, etc.) para determinar a qué solicitudes afecta el script.
- Escriba su lógica de intercepción.
- Después de habilitar el script, comience a capturar paquetes para que surta efecto.
Estructura básica del script
Cada script puede contener dos funciones:
// Intercepción de solicitud (Opcional)
function interceptRequest(request) {
// Tu lógica
return { action: 'passthrough' };
}
// Intercepción de respuesta (Opcional)
function interceptResponse(request, response) {
// Tu lógica
return { action: 'passthrough' };
}
- Puedes definir solo uno de ellos, o definir ambos.
- Los scripts se ejecutan en orden de prioridad y tiempo de creación.
- Una vez que un script devuelve un resultado distinto de
passthrough, los scripts posteriores no se ejecutarán.
Función de intercepción de solicitud interceptRequest
Cuando llega una solicitud HTTP que coincide, se llama a la función interceptRequest.
Parámetros: objeto request
| Propiedad | Tipo | Descripción |
|---|---|---|
method | string | Método HTTP (GET, POST, PUT, DELETE, etc.) |
url | string | URL completa |
host | string | Nombre de host |
port | number | Número de puerto |
path | string | Ruta de la solicitud |
scheme | string | Protocolo (http / https) |
headers | object | Encabezados de solicitud (objeto clave-valor) |
body | string | Cadena del cuerpo de la solicitud |
queryParams | object | Parámetros de consulta de URL (objeto clave-valor) |
Valor de retorno
Devuelve un objeto que contiene un campo action para determinar cómo procesar la solicitud:
1. Permitir el paso de la solicitud (passthrough)
return { action: 'passthrough' };
No hace ninguna modificación, la solicitud se envía normalmente.
2. Modificar la solicitud (modify)
request.headers['Authorization'] = 'Bearer my-token';
request.body = JSON.stringify({ modified: true });
return { action: 'modify', request: request };
Continúa enviando después de modificar el contenido de la solicitud.
3. Simular respuesta (mock)
return {
action: 'mock',
response: {
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ success: true, data: 'mocked' })
}
};
No envía la solicitud real, devuelve directamente la respuesta simulada.
4. Redireccionar (redirect)
return {
action: 'redirect',
url: 'https://new-api.example.com' + request.path,
statusCode: 302 // Opcional, predeterminado 302
};
Redirecciona la solicitud a otra URL.
5. Descartar la solicitud (drop)
return { action: 'drop' };
Descarta la solicitud directamente, sin enviarla ni responderla.
Función de intercepción de respuesta interceptResponse
Después de que el servidor devuelve una respuesta, se llama a la función interceptResponse.
Parámetros
- request: Información de la solicitud original (igual que arriba)
- response: Información de la respuesta
| Propiedad | Tipo | Descripción |
|---|---|---|
statusCode | number | Código de estado HTTP |
headers | object | Encabezados de respuesta (objeto clave-valor) |
body | string | Cadena del cuerpo de la respuesta |
Valor de retorno
1. Permitir el paso de la respuesta (passthrough)
return { action: 'passthrough' };
2. Modificar la respuesta (modify)
var data = JSON.parse(response.body);
data.injected = true;
response.body = JSON.stringify(data);
return { action: 'modify', response: response };
3. Retrasar la respuesta (delay)
return {
action: 'delay',
response: response,
delay: 3000 // Retraso de 3000 milisegundos
};
4. Descartar la respuesta (drop)
return { action: 'drop' };
API integrada
Los siguientes objetos globales están preestablecidos en el entorno del script y se pueden usar directamente en interceptRequest y interceptResponse.
httpClient — Solicitudes HTTP
Inicia solicitudes HTTP/HTTPS dentro del script. La llamada es síncrona, el script esperará a que se complete la solicitud antes de continuar la ejecución. El tiempo que tarda cada solicitud se registrará automáticamente en el registro para facilitar la resolución de problemas de rendimiento.
Métodos
// Solicitud GET
httpClient.get(url)
httpClient.get(url, headers)
// Solicitud POST
httpClient.post(url)
httpClient.post(url, body)
httpClient.post(url, body, headers)
// Solicitud PUT
httpClient.put(url)
httpClient.put(url, body)
httpClient.put(url, body, headers)
// Solicitud DELETE
httpClient.delete(url)
httpClient.delete(url, headers)
Descripción de parámetros
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
url | string | ✅ | URL de solicitud completa (http:// o https://) |
body | string | ❌ | Cadena del cuerpo de la solicitud (para JSON, use JSON.stringify()) |
headers | object | ❌ | Objeto de encabezado de solicitud |
Valor de retorno
Todos los métodos devuelven un objeto de respuesta de la misma estructura:
{
statusCode: 200, // Código de estado HTTP (-1 si la solicitud falla)
headers: { ... }, // Objeto de encabezado de respuesta
body: "...", // Cadena del cuerpo de la respuesta
error: "" // Mensaje de error (cadena vacía si tiene éxito)
}
Ejemplo
// Solicitud GET simple
var resp = httpClient.get('https://api.example.com/status');
console.log('Status: ' + resp.statusCode);
// Solicitud GET con encabezados
var resp = httpClient.get('https://api.example.com/user', {
'Authorization': 'Bearer my-token'
});
// POST de datos JSON
var resp = httpClient.post(
'https://api.example.com/data',
JSON.stringify({ name: 'test', value: 123 }),
{ 'Content-Type': 'application/json' }
);
// Comprobar si la solicitud se realizó con éxito
if (resp.error) {
console.error('La solicitud falló: ' + resp.error);
} else {
var data = JSON.parse(resp.body);
console.log('Datos de respuesta: ' + JSON.stringify(data));
}
Registro automático del tiempo de consumo
Cada vez que se completa una llamada httpClient, el motor emitirá automáticamente un registro:
[Script] httpClient.get https://api.example.com/status -> 200 (156ms)
[Script] httpClient.post https://api.example.com/data -> 201 (342ms)
Puede ver esta información en el panel de registro de APICatcher para ayudar a localizar solicitudes lentas.
⚠️ Nota: Las llamadas a httpClient son síncronas y bloquearán la ejecución del script hasta que se complete la solicitud HTTP (tiempo de espera de 15 segundos). Si inicia una solicitud HTTP que consume mucho tiempo en el script, puede causar un retraso en la respuesta de la solicitud interceptada original. Preste atención a los datos de tiempo de consumo en los registros.
localStore — Almacenamiento local
Proporciona almacenamiento persistente local simple de clave-valor (Key-Value). Los datos se almacenan en UserDefaults de la aplicación y todos los scripts comparten el mismo espacio de almacenamiento. Si necesita aislar datos por Host u otras dimensiones, agregue un prefijo a la clave usted mismo (por ejemplo, request.host + '_token').
Métodos
// Escribir datos
localStore.write(key, value)
// Leer datos
localStore.read(key) // Devuelve string o null
// Eliminar datos
localStore.remove(key)
Descripción de parámetros
| Parámetro | Tipo | Descripción |
|---|---|---|
key | string | El nombre de clave a almacenar |
value | any | El valor a almacenar (se convertirá automáticamente a cadena) |
Descripción del almacenamiento
- Todos los scripts comparten el mismo espacio de almacenamiento
- Los datos se conservan en la zona de pruebas de la aplicación (almacenamiento local) y siguen existiendo después de reiniciar la aplicación
- Si necesita aislar por Host, incluya información del Host en la clave, por ejemplo:
// Aislamiento manual por host
var key = request.host + '_token';
localStore.write(key, 'my-token');
Ejemplo
// Lectura y escritura básicas
localStore.write('counter', '1');
var count = localStore.read('counter'); // '1'
console.log('Count: ' + count);
// Almacenar objeto JSON
var config = { debug: true, maxRetry: 3 };
localStore.write('config', JSON.stringify(config));
// Leer objeto JSON
var raw = localStore.read('config');
if (raw) {
var config = JSON.parse(raw);
console.log('Debug mode: ' + config.debug);
}
// Eliminar datos
localStore.remove('counter');
var v = localStore.read('counter'); // null
console — Salida de registro
Se utiliza para enviar registros dentro del script, que se pueden ver en el panel de registros de API Catcher.
console.log('Registro normal'); // Nivel de información
console.warn('Registro de advertencia'); // Nivel de advertencia
console.error('Registro de error'); // Nivel de error
Admite múltiples parámetros y los objetos se serializarán automáticamente en JSON:
console.log('Información de la solicitud:', request.method, request.url);
console.log('Datos de respuesta:', { status: response.statusCode, body: response.body });
Ejemplos prácticos
Ejemplo 1: Inyección automática de token de autenticación
Intercepte todas las solicitudes a api.myserver.com y agregue automáticamente el encabezado Authorization. El Token se obtiene de la API de inicio de sesión y se almacena en caché en localStore.
function interceptRequest(request) {
// Solo procesar el servidor de destino
if (!request.host.includes('api.myserver.com')) {
return { action: 'passthrough' };
}
// Intentar leer el token del caché
var token = localStore.read('auth_token');
var tokenExpiry = localStore.read('auth_token_expiry');
// Comprobar si el token ha caducado (usando la marca de tiempo, en segundos)
var now = Math.floor(Date.now() / 1000);
if (!token || !tokenExpiry || now > parseInt(tokenExpiry)) {
// El token no existe o ha caducado, vuelva a iniciar sesión para obtenerlo
console.log('Token expired, re-authenticating...');
var loginResp = httpClient.post(
'https://api.myserver.com/auth/login',
JSON.stringify({ username: 'testuser', password: 'testpass' }),
{ 'Content-Type': 'application/json' }
);
if (loginResp.statusCode === 200) {
var loginData = JSON.parse(loginResp.body);
token = loginData.token;
// Caché del token, configúrelo para que caduque en 1 hora
localStore.write('auth_token', token);
localStore.write('auth_token_expiry', String(now + 3600));
console.log('New token cached successfully');
} else {
console.error('Login failed: ' + loginResp.statusCode);
return { action: 'passthrough' };
}
}
// Inyectar encabezado Authorization
request.headers['Authorization'] = 'Bearer ' + token;
return { action: 'modify', request: request };
}
Ejemplo 2: Reenvío de datos de API/Informes de registro
Informe de la información de solicitud y respuesta interceptada a su servidor de análisis de registros.
function interceptResponse(request, response) {
// Solo informar API de rutas específicas
if (!request.path.startsWith('/api/v2/')) {
return { action: 'passthrough' };
}
// Recopilar información de solicitud y respuesta
var logData = {
timestamp: new Date().toISOString(),
request: {
method: request.method,
url: request.url,
headers: request.headers
},
response: {
statusCode: response.statusCode,
body: response.body
}
};
// Informar al servidor de registro (nota: la solicitud es síncrona y bloqueará el retorno de la respuesta actual)
var reportResp = httpClient.post(
'https://log.myserver.com/api/collect',
JSON.stringify(logData),
{ 'Content-Type': 'application/json' }
);
if (reportResp.error) {
console.warn('Log report failed: ' + reportResp.error);
}
// Permitir pasar la respuesta original
return { action: 'passthrough' };
}
Ejemplo 3: Pruebas A/B — Modificar respuestas dinámicamente
Utilice un contador para implementar una división A/B simple, devolviendo alternativamente diferentes datos simulados.
function interceptRequest(request) {
if (request.path !== '/api/recommend') {
return { action: 'passthrough' };
}
// Leer el contador alternativo de localStore
var count = parseInt(localStore.read('ab_counter') || '0');
count++;
localStore.write('ab_counter', String(count));
// Devolver alternativamente diferentes versiones
var version = (count % 2 === 0) ? 'A' : 'B';
if (version === 'A') {
return {
action: 'mock',
response: {
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
version: 'A',
items: [{ id: 1, name: 'Plan de recomendación A-1' }, { id: 2, name: 'Plan de recomendación A-2' }]
})
}
};
} else {
return {
action: 'mock',
response: {
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
version: 'B',
items: [{ id: 3, name: 'Plan de recomendación B-1' }, { id: 4, name: 'Plan de recomendación B-2' }]
})
}
};
}
}
Ejemplo 4: Protección de límite de velocidad de solicitud
Registre la frecuencia de solicitud de la misma API y devuelva el error 429 cuando supere el umbral.
function interceptRequest(request) {
if (!request.path.startsWith('/api/')) {
return { action: 'passthrough' };
}
var key = 'rate_' + request.path;
var now = Math.floor(Date.now() / 1000);
// Leer el tiempo y el conteo de la última solicitud
var rawData = localStore.read(key);
var data = rawData ? JSON.parse(rawData) : { count: 0, windowStart: now };
// Si la ventana de tiempo supera los 60 segundos, restablezca el contador
if (now - data.windowStart > 60) {
data = { count: 0, windowStart: now };
}
data.count++;
localStore.write(key, JSON.stringify(data));
// Máximo 10 veces por minuto
if (data.count > 10) {
console.warn('Rate limit exceeded for ' + request.path);
return {
action: 'mock',
response: {
statusCode: 429,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
error: 'Too Many Requests',
retryAfter: 60 - (now - data.windowStart)
})
}
};
}
return { action: 'passthrough' };
}
Notas
-
httpClient es una llamada síncrona: Las solicitudes HTTP iniciadas en el script bloquearán la ejecución del script hasta que se complete la solicitud o se agote el tiempo de espera (15 segundos). Esto afectará la velocidad de procesamiento de la solicitud original. Preste atención a la información del tiempo de consumo de la solicitud que se genera automáticamente en los registros.
-
Almacenamiento compartido localStore: Todos los scripts comparten el mismo espacio de almacenamiento. Si necesita aislar datos por Host, agregue un prefijo en la clave usted mismo.
-
Orden de ejecución del script: Varios scripts se ordenan y ejecutan por prioridad. Una vez que un script devuelve un resultado distinto de
passthrough, los scripts posteriores se omitirán. -
Scripts remotos: Soporta la carga de scripts desde URL. El contenido del script remoto se extraerá automáticamente al iniciar la captura de paquetes. Si la extracción falla, se omitirá el script.
-
Procesamiento de JSON: El cuerpo de las solicitudes/respuestas son cadenas. Cuando necesite procesar datos JSON, utilice
JSON.parse()para analizar yJSON.stringify()para serializar. -
Manejo de errores: Se recomienda utilizar
try-catchen la lógica clave y registrar las excepciones medianteconsole.error()para evitar que la cadena de intercepción se interrumpa debido a un bloqueo del script. -
Funciones auxiliares: El motor tiene dos funciones de utilidad integradas:
safeJsonParse(str)— Análisis seguro de JSON, devuelve un valor nulo en caso de errordeepClone(obj)— Copia profunda de objetos