Uppy Companion 不适用于超过 5GB 的文件,并使用 Multipart S3 上传
Uppy Companion doesn't work for > 5GB files with Multipart S3 uploads
我们的应用程序允许我们的客户上传大文件。文件存储在 AWS/S3 上,我们使用 Uppy 进行上传,并将其 dockerize 以在 kubernetes 部署下使用,我们可以增加实例的数量。
它运行良好,但我们注意到所有大于 5GB 的上传都失败了。我知道 uppy 有一个用于 AWS 分段上传的插件,但即使在创建容器镜像期间安装,结果也是一样的。
这是我们的 Dockerfile。有没有人通过 uppy 成功地将大于 5GB 的文件上传到 S3?有什么我们遗漏的吗?
FROM node:alpine AS companion
RUN yarn global add @uppy/companion@3.0.1
RUN yarn global add @uppy/aws-s3-multipart
ARG UPPY_COMPANION_DOMAIN=[...redacted..]
ARG UPPY_AWS_BUCKET=[...redacted..]
ENV COMPANION_SECRET=[...redacted..]
ENV COMPANION_PREAUTH_SECRET=[...redacted..]
ENV COMPANION_DOMAIN=${UPPY_COMPANION_DOMAIN}
ENV COMPANION_PROTOCOL="https"
ENV COMPANION_DATADIR="COMPANION_DATA"
# ENV COMPANION_HIDE_WELCOME="true"
# ENV COMPANION_HIDE_METRICS="true"
ENV COMPANION_CLIENT_ORIGINS=[...redacted..]
ENV COMPANION_AWS_KEY=[...redacted..]
ENV COMPANION_AWS_SECRET=[...redacted..]
ENV COMPANION_AWS_BUCKET=${UPPY_AWS_BUCKET}
ENV COMPANION_AWS_REGION="us-east-2"
ENV COMPANION_AWS_USE_ACCELERATE_ENDPOINT="true"
ENV COMPANION_AWS_EXPIRES="3600"
ENV COMPANION_AWS_ACL="public-read"
# We don't need to store data for just S3 uploads, but Uppy throws unless this dir exists.
RUN mkdir COMPANION_DATA
CMD ["companion"]
EXPOSE 3020
编辑:
我确定我有:
uppy.use(AwsS3Multipart, {
limit: 5,
companionUrl: '<our uppy url',
})
它仍然不起作用 - 我看到在网络选项卡上发送了 9GB 文件的所有块,但是一旦达到 100% - uppy 就会抛出错误“无法 post”(到我们的 S3 url) 就是这样。失败。
有人遇到过这种情况吗?上传正常,直到 100%,然后最后一个块 HTTP error 413
,导致整个上传失败。
谢谢!
在单个 PUT 操作中的 AWS S3 服务中,您可以上传最大 5 GB 的单个对象。
要将大于 5GB 的文件上传到 S3,您需要使用分段上传 S3 API,以及 AwsS3Multipart
Uppy API.
检查您的上传代码以了解您是否正确使用 AWSS3Multipart,例如正确设置限制,在这种情况下,建议限制在 5 到 15 之间。
import AwsS3Multipart from '@uppy/aws-s3-multipart'
uppy.use(AwsS3Multipart, {
limit: 5,
companionUrl: 'https://uppy-companion.myapp.net/',
})
此外,请在 Github Uploading a large >5GB file to S3 errors out #1945
上查看此问题
在这里,我从我的存储库中添加了一些代码示例,它们将帮助您了解使用 BUSBOY 包将数据流式传输到 S3 存储桶的流程。另外,我在这里添加了参考链接,供您获取我正在使用的包的详细信息。
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-s3/index.html
https://www.npmjs.com/package/busboy
export const uploadStreamFile = async (req: Request, res: Response) => {
const busboy = new Busboy({ headers: req.headers });
const streamResponse = await busboyStream(busboy, req);
const uploadResponse = await s3FileUpload(streamResponse.data.buffer);
return res.send(uploadResponse);
};
const busboyStream = async (busboy: any, req: Request): Promise<any> {
return new Promise((resolve, reject) => {
try {
const fileData: any[] = [];
let fileBuffer: Buffer;
busboy.on('file', async (fieldName: any, file: any, fileName: any, encoding: any, mimetype: any) => {
// ! File is missing in the request
if (!fileName)
reject("File not found!");
let totalBytes: number = 0;
file.on('data', (chunk: any) => {
fileData.push(chunk);
// ! given code is only for logging purpose
// TODO will remove once project is live
totalBytes += chunk.length;
console.log('File [' + fieldName + '] got ' + chunk.length + ' bytes');
});
file.on('error', (err: any) => {
reject(err);
});
file.on('end', () => {
fileBuffer = Buffer.concat(fileData);
});
});
// ? Haa, finally file parsing wen't well
busboy.on('finish', () => {
const responseData: ResponseDto = {
status: true, message: "File parsing done", data: {
buffer: fileBuffer,
metaData
}
};
resolve(responseData)
console.log('Done parsing data! -> File uploaded');
});
req.pipe(busboy);
} catch (error) {
reject(error);
}
});
}
const s3FileUpload = async (fileData: any): Promise<ResponseDto> {
try {
const params: any = {
Bucket: <BUCKET_NAME>,
Key: <path>,
Body: fileData,
ContentType: <content_type>,
ServerSideEncryption: "AES256",
};
const command = new PutObjectCommand(params);
const uploadResponse: any = await this.S3.send(command);
return { status: true, message: "File uploaded successfully", data: uploadResponse };
} catch (error) {
const responseData = { status: false, message: "Monitor connection failed, please contact tech support!", error: error.message };
return responseData;
}
}
我们的应用程序允许我们的客户上传大文件。文件存储在 AWS/S3 上,我们使用 Uppy 进行上传,并将其 dockerize 以在 kubernetes 部署下使用,我们可以增加实例的数量。
它运行良好,但我们注意到所有大于 5GB 的上传都失败了。我知道 uppy 有一个用于 AWS 分段上传的插件,但即使在创建容器镜像期间安装,结果也是一样的。
这是我们的 Dockerfile。有没有人通过 uppy 成功地将大于 5GB 的文件上传到 S3?有什么我们遗漏的吗?
FROM node:alpine AS companion
RUN yarn global add @uppy/companion@3.0.1
RUN yarn global add @uppy/aws-s3-multipart
ARG UPPY_COMPANION_DOMAIN=[...redacted..]
ARG UPPY_AWS_BUCKET=[...redacted..]
ENV COMPANION_SECRET=[...redacted..]
ENV COMPANION_PREAUTH_SECRET=[...redacted..]
ENV COMPANION_DOMAIN=${UPPY_COMPANION_DOMAIN}
ENV COMPANION_PROTOCOL="https"
ENV COMPANION_DATADIR="COMPANION_DATA"
# ENV COMPANION_HIDE_WELCOME="true"
# ENV COMPANION_HIDE_METRICS="true"
ENV COMPANION_CLIENT_ORIGINS=[...redacted..]
ENV COMPANION_AWS_KEY=[...redacted..]
ENV COMPANION_AWS_SECRET=[...redacted..]
ENV COMPANION_AWS_BUCKET=${UPPY_AWS_BUCKET}
ENV COMPANION_AWS_REGION="us-east-2"
ENV COMPANION_AWS_USE_ACCELERATE_ENDPOINT="true"
ENV COMPANION_AWS_EXPIRES="3600"
ENV COMPANION_AWS_ACL="public-read"
# We don't need to store data for just S3 uploads, but Uppy throws unless this dir exists.
RUN mkdir COMPANION_DATA
CMD ["companion"]
EXPOSE 3020
编辑:
我确定我有:
uppy.use(AwsS3Multipart, {
limit: 5,
companionUrl: '<our uppy url',
})
它仍然不起作用 - 我看到在网络选项卡上发送了 9GB 文件的所有块,但是一旦达到 100% - uppy 就会抛出错误“无法 post”(到我们的 S3 url) 就是这样。失败。
有人遇到过这种情况吗?上传正常,直到 100%,然后最后一个块 HTTP error 413
,导致整个上传失败。
谢谢!
在单个 PUT 操作中的 AWS S3 服务中,您可以上传最大 5 GB 的单个对象。
要将大于 5GB 的文件上传到 S3,您需要使用分段上传 S3 API,以及 AwsS3Multipart
Uppy API.
检查您的上传代码以了解您是否正确使用 AWSS3Multipart,例如正确设置限制,在这种情况下,建议限制在 5 到 15 之间。
import AwsS3Multipart from '@uppy/aws-s3-multipart'
uppy.use(AwsS3Multipart, {
limit: 5,
companionUrl: 'https://uppy-companion.myapp.net/',
})
此外,请在 Github Uploading a large >5GB file to S3 errors out #1945
上查看此问题在这里,我从我的存储库中添加了一些代码示例,它们将帮助您了解使用 BUSBOY 包将数据流式传输到 S3 存储桶的流程。另外,我在这里添加了参考链接,供您获取我正在使用的包的详细信息。
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/clients/client-s3/index.html
https://www.npmjs.com/package/busboy
export const uploadStreamFile = async (req: Request, res: Response) => {
const busboy = new Busboy({ headers: req.headers });
const streamResponse = await busboyStream(busboy, req);
const uploadResponse = await s3FileUpload(streamResponse.data.buffer);
return res.send(uploadResponse);
};
const busboyStream = async (busboy: any, req: Request): Promise<any> {
return new Promise((resolve, reject) => {
try {
const fileData: any[] = [];
let fileBuffer: Buffer;
busboy.on('file', async (fieldName: any, file: any, fileName: any, encoding: any, mimetype: any) => {
// ! File is missing in the request
if (!fileName)
reject("File not found!");
let totalBytes: number = 0;
file.on('data', (chunk: any) => {
fileData.push(chunk);
// ! given code is only for logging purpose
// TODO will remove once project is live
totalBytes += chunk.length;
console.log('File [' + fieldName + '] got ' + chunk.length + ' bytes');
});
file.on('error', (err: any) => {
reject(err);
});
file.on('end', () => {
fileBuffer = Buffer.concat(fileData);
});
});
// ? Haa, finally file parsing wen't well
busboy.on('finish', () => {
const responseData: ResponseDto = {
status: true, message: "File parsing done", data: {
buffer: fileBuffer,
metaData
}
};
resolve(responseData)
console.log('Done parsing data! -> File uploaded');
});
req.pipe(busboy);
} catch (error) {
reject(error);
}
});
}
const s3FileUpload = async (fileData: any): Promise<ResponseDto> {
try {
const params: any = {
Bucket: <BUCKET_NAME>,
Key: <path>,
Body: fileData,
ContentType: <content_type>,
ServerSideEncryption: "AES256",
};
const command = new PutObjectCommand(params);
const uploadResponse: any = await this.S3.send(command);
return { status: true, message: "File uploaded successfully", data: uploadResponse };
} catch (error) {
const responseData = { status: false, message: "Monitor connection failed, please contact tech support!", error: error.message };
return responseData;
}
}