Planteamiento y alcance
Debes procesar cuerpos de solicitud binarios en un navegador o runtime perimetral (edge). La plataforma añade Request.bytes(), pero el cuerpo de una solicitud solo puede consumirse una vez. Explica cuándo usarlo, cómo evitar lecturas dobles, cómo limitar la memoria y cómo diseñar un mecanismo de respaldo (fallback).
MDN describe que Request.bytes() devuelve una Promise cuyo valor cumplido es un Uint8Array del cuerpo de la solicitud; leer un cuerpo lo consume. La entrevista evalúa el tiempo de vida del cuerpo en Fetch, los límites de recursos y los errores, en lugar de tratar el nuevo método como un valor predeterminado universal.
Lo que evalúa el entrevistador
- Explicar el estado de cuerpo usado y la exclusión mutua de
bytes(),arrayBuffer(),json()ytext(). - Elegir entre lecturas completas o mediante streaming según el tamaño de la solicitud y los objetivos de procesamiento.
- Ubicar un único límite de lectura entre reintentos, registro (logging), verificación de firmas y parseo de negocio.
- Diseñar detección de capacidades, límites, cancelación, tiempos de espera (timeouts) y mapeo de errores.
- Evitar que los cuerpos en bruto entren en registros, cachés u objetos compartidos entre inquilinos (tenants).
Preguntas de clarificación
- ¿Cuáles son el tamaño del cuerpo, el origen, el Content-Type, los requisitos de firma y el runtime de destino?
- ¿El negocio necesita un arreglo de bytes completo, hashing incremental, subida por fragmentos o datos decodificados?
- ¿Qué capa realiza los reintentos y es seguro el reenvío (replay)?
- ¿Puede el cuerpo contener datos personales, credenciales o datos con aislamiento por inquilino?
Tiempo de vida del cuerpo y elección de API
Después de que Request.bytes() consume un cuerpo con éxito, las llamadas posteriores a json() o text() fallan, y lo inverso también es cierto. Si varios consumidores necesitan los datos, lee una sola vez en un límite único y pasa resultados controlados al parseo, la verificación y el código de negocio. No pases un objeto Request a través de muchos módulos que compitan por leerlo.
Las lecturas completas son adecuadas para solicitudes pequeñas y acotadas o protocolos que requieren validación en un solo paso. Las solicitudes grandes deben preferir el streaming con request.body, realizando hashing incremental y comprobaciones de tamaño. Un resultado Uint8Array es conveniente para el procesamiento de bytes, pero no elimina el pico de memoria de una lectura completa.
Memoria, límites y contrapresión (backpressure)
Verifica Content-Length en el edge, pero no confíes únicamente en él; con transferencias fragmentadas (chunked), cuenta los bytes reales y aborta cuando se exceda el límite. Establece topes por inquilino, por ruta y globales para las lecturas completas, de modo que las solicitudes concurrentes no puedan asignar arreglos sin límite. Las rutas de streaming aplican contrapresión cuando los consumidores se quedan atrás.
Para el reenvío, no copies múltiples arreglos completos para registro o reintento. Si se requiere reenvío (replay), escribe los bytes con límite de tamaño en un almacenamiento temporal controlado con vinculación al inquilino, expiración y un resumen criptográfico (digest); los cuerpos en bruto no pertenecen a los registros ordinarios.
Verificación de firmas, parseo y errores
Antes de la verificación, define si la firma cubre los bytes en bruto o una estructura canónica. Suministra los bytes en bruto de la única lectura tanto al verificador como al analizador (parser); la reserialización de JSON puede cambiar los espacios en blanco, el orden o la codificación. Mapea fallos de parseo, fallos de firma, violaciones de tamaño, cancelaciones y tiempos de espera a errores de negocio distintos en lugar de una única respuesta de "solicitud malformada".
Las funciones edge pueden exponer diferentes API para el cuerpo. Detecta la capacidad y elige bytes(), arrayBuffer() o streaming, registrando la versión de capacidad del runtime al inicio. Los mecanismos de respaldo deben preservar los límites, el resumen de entrada y la semántica de errores; un runtime antiguo no debe debilitar silenciosamente la seguridad.
Cancelación, tiempos de espera y reenvío
Pasa un AbortSignal a las lecturas y operaciones posteriores. Detén la lectura y libera referencias cuando el cliente se desconecte o expire un plazo. Nunca reenvíes automáticamente una solicitud con efectos secundarios después de un tiempo de espera sin una clave de idempotencia, deduplicación en el servidor y una ventana de reintento explícita. Incluso las consultas aparentemente seguras necesitan una revisión de fugas por reenvío.
Los reintentos en el gateway pueden crear copias de la solicitud, por lo que la verificación de firmas, las claves de idempotencia y los eventos de auditoría deben compartir un único ID de solicitud. Una respuesta de error debe indicar si el reintento es seguro sin exponer el estado interno de lectura ni material de claves.
Seguridad y observabilidad
Limita el Content-Type, el tamaño del cuerpo, la duración de la lectura y la concurrencia. Toma en cuenta el tamaño descomprimido para resistir bombas de descompresión. Aísla las cachés y los objetos temporales por inquilino; conserva los bytes sensibles solo durante el tiempo necesario. Registra el recuento de bytes, la duración, el motivo de cancelación, la clase de error y el resumen de la solicitud, nunca el contenido.
Monitorea los fallos en el consumo del cuerpo, las violaciones de límites, el tiempo de lectura p95, el pico de memoria, la contrapresión descendente y los reintentos. Si los fallos de bytes() aumentan en un runtime, cambia a un respaldo probado y genera una alerta; capturar una excepción y leer el mismo cuerpo nuevamente no constituye una recuperación.
Lista de verificación de validación y seguimiento
Prueba casos vacíos, de un byte, cercanos al límite, que excedan el límite, fragmentados, de cliente lento, desconexión, doble lectura, discrepancia de firma, bomba de descompresión, concurrentes, respaldo en runtime antiguo y tiempos de espera descendentes. Verifica que cada ruta consuma el cuerpo exactamente una vez y que la cancelación detenga lecturas posteriores.
¿Por qué no llamar a json() y luego usar bytes() para la verificación?
La primera lectura ya ha consumido el cuerpo, y el parseo más la reserialización pueden cambiar los espacios en blanco, el orden o la codificación. Lee los bytes en bruto una sola vez y suministra esos mismos bytes para la verificación y el parseo.
¿Cuándo es preferible bytes() frente al streaming?
Úsalo para solicitudes pequeñas y acotadas cuando el protocolo requiera una validación de bytes completa. Los archivos grandes, las subidas continuas y la alta concurrencia necesitan streaming y procesamiento incremental.
¿Cómo demuestras que el mecanismo de respaldo es igualmente seguro?
Fuerza cada ruta de capacidad en cada runtime y compara límites, resúmenes, firmas, errores, cancelación y eventos de auditoría. El mecanismo de respaldo no debe alterar la política de seguridad ni los límites de reintento.