Flutter/Dart carga un archivo zip multipartida prefirmado en S3 y añade un encabezado adicional, lo cual provoca que el archivo zip no se pueda descomprimir.
Estoy tratando de cargar un archivo zip a AWS S3 con una URL prefirmada.
Obtengo la URL prefirmada que parece funcionar muy bien con Postman. Con Flutter también funciona, hasta cierto punto.
Sin embargo, el problema es que al cargar a través de Flutter (utilicé este fragmento), cargará el archivo zip, pero agregará 184 bytes adicionales al encabezado que contiene lo siguiente:
–dart-http-boundary-z86XWhmTq935Bbfwfv.7UA+FIOU5nE4eqfUsZTh6PnGj+HBeAYH
content-type: application/octet-stream
content-disposition: form-data; name=”out.zip”; filename=”out.zip”
Este encabezado hace que la mayoría de las herramientas integradas de descompresión no puedan descomprimir el archivo.
Pude descomprimirlo usando el comando unzip integrado de osx, pero al descargarlo a través de Safari, por ejemplo, obtengo el mensaje “Fallo en la descompresión” en la sección de descargas.
En Windows no pude descomprimirlo en absoluto, incluso con 7-Zip.
¿Hay alguna manera de eliminar el encabezado para que cargue solo el archivo zip tal como está sin agregar encabezados adicionales?
Aviso legal: No soy un desarrollador Flutter/Dart por naturaleza.
¡Gracias!
EDIT 1:
Para crear la URL firmada (siguiendo la documentación de AWS), uso la siguiente función lambda:
'use strict'
const AWS = require('aws-sdk');
AWS.config.update({ region: process.env.AWS_REGION });
const s3 = new AWS.S3();
const URL_EXPIRATION_SECONDS = 300;
exports.handler = async function(event, context, callback) {
const body = event.body || {};
return await getUploadURL(JSON.parse(event.body).projectNumber)
}
const getUploadURL = async function(projectNumber) {
let Key = `${projectNumber}.zip`;
if (!projectNumber) {
const randomID = parseInt(Math.random() * 10000000)
Key = `${randomID}.zip`;
}
// Obtener la URL firmada de S3
const s3Params = {
Bucket: process.env.UploadBucket,
Key,
Expires: URL_EXPIRATION_SECONDS,
ContentType: 'application/zip',
// Este ACL hace que el objeto cargado sea de lectura pública. También debe descomentar
// el permiso adicional para la función Lambda en la plantilla SAM.
// ACL: 'public-read'
}
console.log('Params: ', s3Params)
const uploadURL = await s3.getSignedUrlPromise('putObject', s3Params)
return JSON.stringify({
uploadURL: uploadURL,
Key
})
}
davy.ai
Parece que el problema que estás enfrentando está relacionado con los encabezados
content-type
ycontent-disposition
que son automáticamente agregados por la bibliotecahttp
de Flutter al enviar la solicitud multipartes. Estos encabezados son necesarios para que el servidor interprete correctamente la solicitud y extraiga los datos del archivo del mensaje multipartes, pero pueden causar problemas al intentar descomprimir el archivo cargado.Para solucionar este problema, puedes intentar modificar la solicitud
http
para excluir los encabezadoscontent-type
ycontent-disposition
utilizando el métodohttp.MultipartFile.fromBytes
en lugar dehttp.MultipartFile.fromPath
. Este método te permite especificar los datos del archivo como bytes sin encabezados adicionales.Aquí tienes un ejemplo de cómo puedes modificar el fragmento de código que proporcionaste para usar
http.MultipartFile.fromBytes
:Esto debería permitirte cargar el archivo en S3 sin encabezados adicionales, lo que debería evitar problemas al descomprimir el archivo.