Saltar al contenido principal


Actualizado

Chrome 85 tiene una implementación experimental de flujos de solicitudes, lo que significa que puede comenzar a realizar una solicitud antes de tener todo el cuerpo disponible.

Podrías usar esto para:

  • Calienta el servidor. En otras palabras, puede iniciar la solicitud una vez que el usuario enfoca un campo de entrada de texto y quitar todos los encabezados, luego esperar hasta que el usuario presione ‘enviar’ antes de enviar los datos que ingresaron.
  • Envíe gradualmente datos generados en el cliente, como audio, video o datos de entrada.
  • Recrea los sockets web a través de HTTP.

Pero dado que se trata de una función de plataforma web de bajo nivel, no se limite a mi ideas. Tal vez pueda pensar en un caso de uso mucho más interesante para la transmisión de solicitudes.

Pruebe las secuencias de solicitudes

Habilitar el apoyo durante la fase de prueba de origen

Los flujos de solicitudes de recuperación están disponibles en una prueba de origen a partir de Chrome 85. Se espera que la prueba de origen finalice en Chrome 87.

Las pruebas de Origin le permiten probar nuevas funciones y brindar comentarios sobre su usabilidad, practicidad y efectividad a la comunidad de estándares web. Para obtener más información, consulte el Guía de pruebas de Origin para desarrolladores web. Para inscribirse en esta u otra prueba de origen, visite el página de registro.

Regístrese para la prueba de origen

  1. Solicita un token por tu origen.
  2. Agrega el token a tus páginas. Hay dos maneras de hacerlo:
    • Agregar un origin-trial <meta> etiqueta al encabezado de cada página. Por ejemplo, esto puede verse así:
      <meta http-equiv="origin-trial" content="TOKEN_GOES_HERE">
    • Si puede configurar su servidor, también puede agregar el token usando un Origin-Trial Encabezado HTTP. El encabezado de respuesta resultante debería verse así:
      Origin-Trial: TOKEN_GOES_HERE

Habilitación a través de chrome: // flags

Pruebe las transmisiones de solicitudes en Chrome 85 girando una bandera experimental:
enable-experimental-web-platform-features.

Manifestación

Esto muestra cómo puede transmitir datos del usuario al servidor y enviar datos que se pueden procesar en tiempo real.

Sí, vale, no es el ejemplo más imaginativo, solo quería mantenerlo simple, ¿de acuerdo?

De todos modos, ¿cómo funciona esto?

Anteriormente en las emocionantes aventuras de fetch streams

Respuesta Las transmisiones han estado disponibles en todos los navegadores modernos durante un tiempo. Le permiten acceder a partes de una respuesta a medida que llegan del servidor:

const response = await fetch(url);
const reader = response.body.getReader();

while (true) {
const { value, done } = await reader.read();
if (done) break;
console.log('Received', value);
}

console.log('Response fully received');

Cada value es un Uint8Array de bytes. La cantidad de matrices que obtiene y el tamaño de las matrices depende de la velocidad de la red. Si tiene una conexión rápida, obtendrá menos «fragmentos» de datos más grandes. Si tiene una conexión lenta, obtendrá más fragmentos más pequeños.

Si desea convertir los bytes en texto, puede usar
TextDecodero la transmisión de transformación más reciente si su los navegadores de destino lo admiten:

const response = await fetch(url);
const reader = response.body
.pipeThrough(new TextDecoderStream())
.getReader();

TextDecoderStream es una corriente de transformación que atrapa a todos esos Uint8Array
fragmenta y los convierte en cadenas.

Las transmisiones son excelentes, ya que puede comenzar a actuar sobre los datos a medida que llegan. Por ejemplo, si recibe una lista de 100 ‘resultados’, puede mostrar el primer resultado tan pronto como lo reciba, en lugar de esperar los 100.

De todos modos, eso es flujos de respuesta, lo nuevo y emocionante de lo que quería hablar es el flujo de solicitudes.

Cuerpos de solicitud de transmisión

Las solicitudes pueden tener cuerpos:

await fetch(url, {
method: 'POST',
body: requestBody,
});

Anteriormente, necesitaba todo el cuerpo listo para comenzar antes de poder iniciar la solicitud, pero ahora en Chrome 85 puede proporcionar el suyo ReadableStream de datos:

function wait(milliseconds) {
return new Promise((resolve) => setTimeout(resolve, milliseconds));
}

const stream = new ReadableStream({
async start(controller) {
await wait(1000);
controller.enqueue('This ');
await wait(1000);
controller.enqueue('is ');
await wait(1000);
controller.enqueue('a ');
await wait(1000);
controller.enqueue('slow ');
await wait(1000);
controller.enqueue('request.');
controller.close();
},
}).pipeThrough(new TextEncoderStream());

fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'text/plain' },
body: stream,
});

Lo anterior enviará «Esta es una solicitud lenta» al servidor, una palabra a la vez, con una pausa de un segundo entre cada palabra.

Cada parte del cuerpo de una solicitud debe ser un Uint8Array de bytes, entonces estoy usando
pipeThrough(new TextEncoderStream()) para hacer la conversión por mí.

Flujos grabables

A veces es más fácil trabajar con transmisiones cuando tienes una WritableStream. Puede hacer esto usando una secuencia de ‘identidad’, que es un par legible / escribible que toma todo lo que se pasa a su final de escritura y lo envía al final de lectura. Puede crear uno de estos creando un TransformStream sin ningún argumento:

const { readable, writable } = new TransformStream();

const responsePromise = fetch(url, {
method: 'POST',
body: readable,
});

Ahora, todo lo que envíe a la secuencia de escritura será parte de la solicitud. Esto le permite componer transmisiones juntos. Por ejemplo, aquí hay un ejemplo tonto en el que los datos se obtienen de una URL, se comprimen y se envían a otra URL:


const response = await fetch(url1);
const { readable, writable } = new TransformStream();


response.body
.pipeThrough(new CompressionStream('gzip'))
.pipeTo(writable);


await fetch(url2, {
method: 'POST',
body: readable,
});

El ejemplo anterior usa flujos de compresión para comprimir datos arbitrarios usando gzip.

Detección de características

Si proporciona un objeto de cuerpo que el navegador no maneja específicamente, llamará toString() en el objeto y utilice el resultado como cuerpo. Si el navegador no admite secuencias de solicitudes, eso significa que el cuerpo de la solicitud se convierte en
"[object ReadableStream]" – probablemente no sea lo que desea enviar al servidor. Para evitar esto, use la detección de características:

const supportsRequestStreams = !new Request('', {
body: new ReadableStream(),
method: 'POST',
}).headers.has('Content-Type');

if (supportsRequestStreams) {
} else {
}

Esto funciona porque el navegador agrega un Content-Type encabezado de
text/plain;charset=UTF-8 a la solicitud si el cuerpo es texto. El navegador solo trata el cuerpo como texto si no flujos de solicitud de soporte, de lo contrario no agregará un Content-Type encabezado en absoluto.

Restricciones

Las solicitudes de transmisión son un nuevo poder para la web, por lo que vienen con algunas restricciones:

Redireccionamientos restringidos

Algunas formas de redireccionamiento HTTP requieren que el navegador vuelva a enviar el cuerpo de la solicitud a otra URL. Para admitir esto, el navegador tendría que almacenar en búfer el contenido de la transmisión, lo que anula el punto, por lo que no hace eso.

En cambio, si la solicitud tiene un cuerpo de transmisión y la respuesta es una redirección HTTP distinta de 303, la recuperación se rechazará y la redirección no ser seguido.

Se permiten redirecciones 303, ya que cambian explícitamente el método a GET y descartar el cuerpo de la solicitud.

HTTP / 2 solo por defecto

De forma predeterminada, la recuperación se rechazará si la conexión no es HTTP / 2. Si desea utilizar solicitudes de transmisión a través de HTTP / 1.1, debe participar:

await fetch(url, {
method: 'POST',
body: stream,
allowHTTP1ForStreamingUpload: true,
});

Precaución:
allowHTTP1ForStreamingUpload no es estándar y solo se utilizará como parte de la implementación experimental de Chrome.

De acuerdo con las reglas HTTP / 1.1, los organismos de solicitud y respuesta deben enviar un
Content-Length encabezado, para que el otro lado sepa cuántos datos recibirá, o cambie el formato del mensaje para usar codificación fragmentada. Con la codificación fragmentada, el cuerpo se divide en partes, cada una con su propia longitud de contenido.

La codificación fragmentada es bastante común cuando se trata de HTTP / 1.1 respuestas, pero muy raro cuando se trata de peticiones. Debido a esto, Chrome está un poco preocupado por la compatibilidad, por lo que está habilitado por ahora.

Esto no es un problema para HTTP / 2, ya que los datos HTTP / 2 siempre están ‘fragmentados’, aunque llama a los fragmentos
marcos. La codificación fragmentada no se introdujo hasta HTTP / 1.1, por lo que las solicitudes con cuerpos de transmisión siempre fallarán en las conexiones HTTP / 1.

Dependiendo de cómo vaya esta prueba, la especificación restringirá las respuestas de transmisión a HTTP / 2 o siempre lo permitirá tanto para HTTP / 1.1 como para HTTP / 2.

Sin comunicación dúplex

Una característica poco conocida de HTTP (aunque, si este es un comportamiento estándar depende de a quién le pregunte) es que puede comenzar a recibir la respuesta mientras aún envía la solicitud. Sin embargo, es tan poco conocido que no está bien soportado por servidores y, bueno, navegadores.

En la implementación actual de Chrome, no obtendrá la respuesta hasta que el cuerpo se haya enviado por completo. En el siguiente ejemplo responsePromise no se resolverá hasta que se haya cerrado la transmisión legible. Todo lo que el servidor envíe antes de ese punto se almacenará en búfer.

const responsePromise = fetch(url, {
method: 'POST',
body: readableStream,
});

La segunda mejor opción para la comunicación dúplex es realizar una búsqueda con una solicitud de transmisión y luego realizar otra búsqueda para recibir la respuesta de transmisión. El servidor necesitará alguna forma de asociar estas dos solicitudes, como un ID en la URL. Así es como funciona la demostración.

Problemas potenciales

Sí, entonces … esta es una característica nueva, y hoy en día no se utiliza mucho en Internet. A continuación, se indican algunos problemas que debe tener en cuenta:

Incompatibilidad en el lado del servidor

Algunos servidores de aplicaciones no admiten solicitudes de transmisión, y en su lugar esperan a que se reciba la solicitud completa antes de permitirle ver algo, lo que frustra el punto. En su lugar, utilice un servidor de aplicaciones que admita la transmisión, como
NodeJS.

¡Pero aún no estás fuera de peligro! El servidor de aplicaciones, como NodeJS, normalmente se encuentra detrás de otro servidor, a menudo llamado «servidor de aplicaciones para el usuario», que a su vez puede estar detrás de un CDN. Si alguno de ellos decide almacenar en búfer la solicitud antes de entregarla al siguiente servidor de la cadena, perderá el beneficio de la transmisión de solicitudes.

Además, si está utilizando HTTP / 1.1, es posible que uno de los servidores no esté preparado para la codificación fragmentada y puede fallar con un error. Pero bueno, al menos puedes probar eso e intentar cambiar de servidor si es necesario.

… largo suspiro …

Incompatibilidad fuera de su control

Si está utilizando HTTPS, no necesita preocuparse por los proxies entre usted y el usuario, pero el usuario puede estar ejecutando un proxy en su máquina. Algún software de protección de Internet hace esto para permitirle monitorear todo lo que ocurre entre el navegador y la red.

Puede haber casos en los que los búferes de este software soliciten cuerpos, o en el caso de HTTP / 1.1, no espere una codificación fragmentada y se rompa de alguna manera interesante.

En este momento, no está claro con qué frecuencia sucederá esto, si es que ocurrirá.

Si desea protegerse contra esto, puede crear una ‘prueba de características’ similar a la demostración anterior, donde intenta transmitir algunos datos sin cerrar la transmisión. Si el servidor recibe los datos, puede responder a través de una búsqueda diferente. Una vez que esto sucede, sabrá que el cliente admite solicitudes de transmisión de un extremo a otro.

Comentarios bienvenidos

Los comentarios de la comunidad son cruciales para el diseño de nuevas API, así que pruébelo y díganos lo que piensa. Si encuentra algún error, por favor Reportalos, pero si tiene comentarios generales, envíelos al blink-network-dev Grupo de Google.

Foto por Laura Lefurgey-Smith
en
Unsplash

R Marketing Digital