Cómo modificar mensajes WebSocket con Scripting en Proxyman

Imagen de portada de Cómo modificar mensajes WebSocket con Scripting en Proxyman

6 min de lectura

Proxyman ya puede modificar mensajes WebSocket al instante 🎉

Con unas pocas líneas de JavaScript, puedes editar un mensaje, descartarlo o enviar uno nuevo. Funciona con WS y WSS, en ambas direcciones: del cliente al servidor y del servidor al cliente.

En este blog veremos:

  • El problema de probar apps WebSocket.
  • Qué hace la nueva opción Modify WebSocket Messages.
  • Una demostración paso a paso con un servidor WebSocket local que puedes ejecutar tú mismo.
  • Plantillas WebSocket listas para usar, y consejos para cuando nada cambia.

Modify WebSocket Messages es nuevo en Proxyman para macOS. Actualiza a la última versión desde la página de descargas para seguir esta guía.

Este es el resultado. El servidor envía un precio real de BTC, pero la app recibe $1. Cuando la app envía una contraseña, Proxyman descarta el mensaje y responde a la app con una advertencia:

1. El problema

Las apps de chat, trading, juegos y paneles en vivo usan WebSocket para recibir datos en tiempo real. Probarlas es difícil:

  • No puedes controlar el servidor. Envía datos reales. Para que envíe un caso límite, como un precio de 0 o un mensaje de error, hay que cambiar el código del servidor.
  • Algunos casos son difíciles de reproducir. Un mensaje perdido, una respuesta extraña o una conexión caída rara vez ocurren cuando los necesitas.
  • Antes, Proxyman solo podía leer los mensajes WebSocket. La función onWebsocket() de Scripting podía registrar un mensaje, pero no modificarlo.

2. ¿Qué es “Modify WebSocket Messages”?

Es una nueva casilla en una regla de Scripting. Cuando está activada, Proxyman retiene cada mensaje WebSocket hasta que tu función onWebsocket() devuelve un valor. Lo que devuelvas determina lo que ocurre:

En onWebsocket()Resultado
return messageEnvía el mensaje con tus cambios
return nullDescarta el mensaje. El otro extremo nunca lo recibe
Sin returnEnvía el mensaje original
abort()Cierra el WebSocket en ambos lados
sendToClient(data) / sendToServer(data)Envía un mensaje nuevo. Un String envía un mensaje de texto y un Uint8Array, un mensaje binario

El objeto message tiene:

CampoValor
message.from"client" o "server"
message.type"text", "binary", "ping", "pong" o "close"
message.dataEl texto del mensaje. Cámbialo para editar un mensaje de texto
message.rawDataLos bytes de un mensaje binario, como un Uint8Array

La opción está desactivada de forma predeterminada. Cuando está desactivada, onWebsocket() funciona como antes: solo lee los mensajes y nunca los retrasa.

3. Paso a paso: modificar un WebSocket en vivo

Vamos a crear la demostración del video: un pequeño servidor que envía precios de BTC y un cliente que se comunica con él a través de Proxyman.

3.1 Inicia un servidor WebSocket

Crea una carpeta nueva e instala el paquete ws:

mkdir websocket-demo && cd websocket-demo
npm init -y
npm install ws

Guárdalo como server.js. Envía un precio cada segundo y reenvía cada mensaje del chat:

// server.js: a WebSocket server on ws://localhost:3456
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 3456 });

server.on('connection', (socket) => {
  // Send a BTC price every second
  const timer = setInterval(() => {
    const price = Number((67000 + Math.random() * 1000).toFixed(2));
    socket.send(JSON.stringify({ type: 'price', symbol: 'BTC', price: price }));
  }, 1000);

  // Print what the client sends, then echo it back
  socket.on('message', (data) => {
    console.log('SERVER gets:', data.toString());
    socket.send(JSON.stringify({ type: 'echo', text: JSON.parse(data).text }));
  });

  socket.on('close', () => clearInterval(timer));
});

console.log('WebSocket server on ws://localhost:3456');

Ejecútalo en la Terminal:

node server.js

3.2 Conecta un cliente a través de Proxyman

Node.js no usa la configuración de proxy de macOS, así que el cliente envía su handshake WebSocket directamente a Proxyman. Guárdalo como client.js:

// client.js: connects to the server through Proxyman
const http = require('http');
const WebSocket = require('ws');

// Proxyman's port. You can see it in the Proxyman toolbar
const PROXYMAN_PORT = 9090;

// Sends the WebSocket handshake to Proxyman, like an app that uses an HTTP proxy
class ProxymanAgent extends http.Agent {
  addRequest(request, options) {
    request.path = 'http://' + options.host + ':' + options.port + request.path;
    super.addRequest(request, { ...options, host: '127.0.0.1', port: PROXYMAN_PORT });
  }
}

const socket = new WebSocket('ws://localhost:3456/prices', { agent: new ProxymanAgent() });

socket.on('open', () => {
  setTimeout(() => socket.send(JSON.stringify({ type: 'chat', text: 'Hello' })), 2000);
  setTimeout(() => socket.send(JSON.stringify({ type: 'chat', text: 'my password is hunter2' })), 4000);
});

socket.on('message', (data) => console.log('CLIENT gets:', data.toString()));

Abre Proxyman y luego ejecuta el cliente en una segunda Terminal:

node client.js

Verás ws://localhost:3456/prices en Proxyman. Abre su pestaña Websocket para ver los mensajes. Todavía no se ha modificado nada. Detén el cliente con Ctrl+C.

3.3 Crea una regla de Scripting

  1. En Proxyman, haz clic con el botón derecho en el flujo ws://localhost:3456/prices → Tools → Scripting.... Proxyman crea una regla con la URL ya rellenada.
  2. Deja marcada la opción Request y marca Modify WebSocket Messages.
  3. Reemplaza el script por el código siguiente y pulsa Save & Activate (⌘S).
El editor de scripts de Proxyman con Modify WebSocket Messages marcada y un script onWebsocket()
El editor de scripts de Proxyman con Modify WebSocket Messages marcada y un script onWebsocket()
function onWebsocket(context, url, request, response, message) {
  // Only change text messages. Binary, ping, pong, and close messages pass through
  if (message.type !== "text") {
    return message;
  }

  const json = JSON.parse(message.data);

  // 1. Server → client: every BTC price becomes $1
  if (message.from === "server" && json.type === "price") {
    json.price = 1;
    json.note = "edited by Proxyman";
    message.data = JSON.stringify(json);
    return message;
  }

  // 2. Client → server: drop a message with a password, and warn the client
  if (message.from === "client" && json.text.includes("password")) {
    sendToClient(JSON.stringify({ type: "warning", text: "Proxyman blocked a password" }));
    return null;
  }

  // 3. Everything else: send it as it is
  return message;
}

3.4 Ejecútalo de nuevo y revisa el resultado

Ejecuta node client.js de nuevo. Proxyman decide si aplica la opción cuando se conecta el WebSocket, así que vuelve a conectar siempre después de guardar una regla.

Ahora el cliente recibe "price": 1 con la nota "edited by Proxyman". El mensaje con la contraseña nunca llega al servidor: la Terminal del servidor solo imprime Hello, y el cliente recibe en su lugar la advertencia del script.

Izquierda: lo que el cliente y el servidor realmente envían y reciben. Derecha: la pestaña Websocket de Proxyman con los precios editados
Izquierda: lo que el cliente y el servidor realmente envían y reciben. Derecha: la pestaña Websocket de Proxyman con los precios editados

En Proxyman, la pestaña Websocket muestra los precios editados, la advertencia enviada por el script y el mensaje con la contraseña que se descartó.

La ventana principal de Proxyman con el flujo ws://localhost:3456/prices y sus mensajes WebSocket editados
La ventana principal de Proxyman con el flujo ws://localhost:3456/prices y sus mensajes WebSocket editados

4. Más ejemplos

Reemplaza texto en ambas direcciones, por ejemplo, para cambiar el nombre de un host:

const FIND_REGEX = /staging\.example\.com/g;
const REPLACE_WITH = "api.example.com";

function onWebsocket(context, url, request, response, message) {
  if (message.type === "text") {
    message.data = message.data.replace(FIND_REGEX, REPLACE_WITH);
  }
  return message;
}

Simula una conexión perdida tras 10 mensajes, para probar cómo se reconecta tu app. El código fuera de la función se ejecuta una vez por conexión, así que cada conexión cuenta sus propios mensajes:

const CLOSE_AFTER_MESSAGES = 10;
let messageCount = 0;

function onWebsocket(context, url, request, response, message) {
  messageCount += 1;
  if (messageCount === CLOSE_AFTER_MESSAGES) {
    console.log("Closing the WebSocket after " + messageCount + " messages");
    abort();
  }
  return message;
}

Cambia un mensaje binario asignando nuevos bytes:

function onWebsocket(context, url, request, response, message) {
  if (message.type === "binary" && message.from === "server") {
    message.rawData = new Uint8Array([1, 2, 3]);
  }
  return message;
}

5. Empieza más rápido con plantillas WebSocket

No hace falta escribir el script desde cero. En el editor de scripts, haz clic en Templates y busca “websocket”:

  • Log WebSocket Messages: imprime cada mensaje en el Console Log. Solo lee los mensajes.
  • Modify JSON WebSocket Messages: cambia un campo de los mensajes JSON enviados por el servidor.
  • Replace Text in WebSocket Messages: busca y reemplaza texto en ambas direcciones.
  • Drop WebSocket Messages: descarta los mensajes que coincidan con una expresión regular, por ejemplo, los eventos de analítica.
  • Reply to a WebSocket Message: responde a un mensaje del cliente con sendToClient(). El servidor nunca lo recibe.
  • Simulate a WebSocket Disconnect: cierra el WebSocket después de unos pocos mensajes.

Haz clic en Replace para usar una plantilla. Proxyman también marca las casillas necesarias, incluida Modify WebSocket Messages.

La hoja Script Templates de Proxyman, filtrada por las plantillas WebSocket
La hoja Script Templates de Proxyman, filtrada por las plantillas WebSocket

6. Problemas y soluciones

Los mensajes no cambian

  • Marca Modify WebSocket Messages y luego pulsa Save & Activate (⌘S).
  • Vuelve a conectar el WebSocket. La opción se lee cuando el WebSocket se conecta, no en cada mensaje.
  • Mantén marcada Request o Response. Una regla con ambas desmarcadas no se ejecuta en absoluto, ni siquiera onWebsocket().
  • Abre el Console Log del editor de scripts. Si tu script produce un error, Proxyman envía el mensaje original e imprime el error allí.

No veo mi WebSocket en Proxyman

  • Para wss://, activa SSL Proxying para el dominio, igual que para HTTPS.
  • Muchas apps y bibliotecas omiten el proxy para localhost. Envía el tráfico a Proxyman como lo hace client.js, o sigue la documentación de WebSocket para tu plataforma.

Bueno saber

  • Solo el WebSocket que coincide con la regla espera al script. El resto del tráfico sigue fluyendo.
  • Un mensaje de más de 16 MB se envía tal cual, sin pasar por el script.
  • Si usas un agente de IA, Proxyman MCP puede crear la misma regla: create_scripting_rule acepta modify_websocket_messages: true.

Más información

Noah Tran
Noah Tran

Modifica tus mensajes WebSocket sin tocar el servidor

Activa Modify WebSocket Messages en una regla de Scripting y prueba cada mensaje que tu app debe manejar.

Descargar Proxyman para macOS