Estoy tratando de enviar varios archivos desde el cliente al servidor NodeJS usando WebSockets.
Para enviar un archivo, actualmente hago lo siguiente:
// Client let upload = document.getElementById('upload') button.onclick = async function() { let file = upload.files[0]; let byteFile = await getAsByteArray(file); socket.send(byteFile); } async function getAsByteArray(file) { return new Uint8Array(await readFile(file)) } function readFile(file) { return new Promise((resolve, reject) => { let reader = new FileReader() reader.addEventListener("loadend", e => resolve(e.target.result)) reader.addEventListener("error", reject) reader.readAsArrayBuffer(file) }); } // Server ws.on('message', function incoming(message) { // This returns a buffer which is what I'm looking for when working with a single file. console.log(message); return; }Esto funciona muy bien para un archivo. Puedo usar el búfer y procesar el archivo como me gustaría. Para enviar dos archivos, pensé en convertir cada archivo en un Uint8Array (como hice con el archivo único) y enviarlo a una matriz como esta:
// Client let filesArray = []; let files = upload.files; // Grab uploaded Manifests for (let file of files) { let byteFile = await getAsByteArray(file); filesArray.push(byteFile); } socket.send(filesArray);De la misma manera que con un archivo, el servidor devuelve un búfer para la matriz que se envió; sin embargo, no estoy seguro de cómo trabajar con él. Necesito que cada archivo sea su propio búfer para poder trabajar con ellos. ¿Estoy tomando el enfoque equivocado aquí? ¿O simplemente me falta alguna conversión para poder trabajar con cada archivo?
Envíe cada búfer en un mensaje separado:
button.onclick = async function() { upload.files.forEach(file => socket.send(await getAsByteArray(file))); }Esto funciona muy bien para un archivo.
Realmente no. A menos que se suponga que debe usarse en una configuración muy simple, probablemente en una red aislada (de Internet).
Literalmente envías una secuencia de bytes al servidor que los lee y ¿qué va a hacer con ellos? ¿Guardarlo en el disco? Sin validar? Pero, ¿cómo puede validar una secuencia aleatoria de bytes, no tiene ninguna pista sobre lo que es? En segundo lugar, ¿dónde lo guardará? ¿Bajo que nombre? No enviaste ningún metadato como nombre de archivo. ¿Se supone que debe generar un nombre aleatorio para él? ¿Cómo sabrá el usuario que este es su expediente? Diablos, ya que ni siquiera sabes quién envió ese archivo (sin autenticación). Finalmente, ¿qué pasa con la seguridad? ¿Puedo abrir una conexión WebSocket a su servidor y enviarle spam con secuencias arbitrarias de datos, eliminándolo efectivamente? Probablemente necesite alguna autenticación, pero incluso con ella, ¿algún usuario puede enviar spam a tal carga? Tal vez también necesite tokens con tiempos de espera para eso (pero luego debe pensar en cómo su servidor emitirá dichos tokens).
Necesito que cada archivo sea su propio búfer para poder trabajar con ellos.
No, no lo haces. Lo mínimo que necesita es (1) la capacidad de enviar archivos con metadatos desde el cliente y (2) la capacidad de leer archivos con metadatos en el lado del servidor. Lo más probable es que también necesite algún mecanismo de autenticación. Por lo general, usaría HTTP clásico para eso, lo que le recomiendo encarecidamente que utilice.
Si desea seguir con WebSockets, debe implementar esos mecanismos ya bien establecidos por su cuenta. Así que así es como lo haría:
(1) Defina un protocolo personalizado sobre WebSocket. Cada cuadro debe tener una estructura, por ejemplo, los primeros dos bytes que indican "tamaño del comando", los siguientes X bytes (los 2 bytes anteriores interpretados como int de tamaño 16) el comando como cadena. En el lado del servidor, lee ese comando, lo asigna a algún controlador y ejecuta la acción apropiada. Los datos que debe procesar el comando son los datos de los bytes restantes del marco.
(2) Autenticación de configuración. No está en el alcance de esta respuesta, solo indicar que es crucial. Estoy poniendo esto después de (1) porque puedes reutilizar el protocolo para eso.
(3) Siempre que desee cargar un archivo: envíe un comando "ENVIAR" al servidor. En el mismo marco, después del comando "ENVIAR" coloque los metadatos (nombre de archivo, tamaño, tipo de contenido, etc.), puede codificarlos como JSON con el prefijo de longitud. Luego coloque el contenido del archivo en el búfer.
Obviamente, esta solución debe refinarse con tokens (mencionados anteriormente). Para una capacidad de respuesta y concurrencia adecuadas, probablemente debería dividir archivos grandes en marcos WebSocket separados (lo que complica mucho el diseño).
De todos modos, como puede ver, el tema está lejos de ser trivial y requiere mucha experiencia. Y básicamente está reimplementando lo que hace HTTP de todos modos. Nuevamente: le sugiero encarecidamente que use HTTP antiguo y simple.