首页 > 解决方案 > 在浏览器中直接对 S3 URI 执行 GET 时如何从 AWS 读取二进制数据响应?

问题描述

一些一般背景:这是一个使用 MERN 堆栈的应用程序,但问题更具体到 AWS S3 数据。

我有一个 S3 设置,并在那里存储我的应用程序中的图像和文件。我通常使用服务器生成签名 URL,并从浏览器直接上传。

在我的应用程序数据库中,我将对象 URI 存储为一个字符串,然后是一个图像,例如我可以用<img/>标签渲染没有问题。到现在为止还挺好。

但是,当它们是 PDF 并且我想让用户下载我存储在 S3 中的 PDF 时,这样做<a href={s3Uri} download>只会导致 pdf 在另一个窗口/选项卡中打开,而不是提示用户下载。我相信这是由于下载属性依赖于同源并且您无法从外部资源下载文件(如果我错了请纠正我)

那么我的下一个尝试是直接使用 axios 对资源进行 http 获取,它看起来像这样

axios.create({
                baseURL: attachment.fileUrl,
                headers: {common: {Authorization: ''}}
            })
  .get('')
   .then(res => {
        console.log(res)
        console.log(typeof res.data)
        console.log(new Buffer.from(res.data).toString())
    })

因此,通过这样做,我成功读取了响应标头(很有用,因为这样我可以以不同的方式处理图像/文件)但是当我尝试读取返回的二进制数据时,我没有成功并解析它甚至确定它是如何编码的,它看起来像这样

%PDF-1.3
3 0 obj
<</Type /Page
/Parent 1 0 R
/Resources 2 0 R
/Contents 4 0 R>>
endobj
4 0 obj
<</Filter /FlateDecode /Length 1811>>
stream
x�X�R�=k=E׷�������Na˅��/���� �[�]��.�,��^ �wF0�.��Ie�0�o��ݧO_IoG����p��4�BJI���g��d|��H�$�12(R*oB��:%먺�����:�R�Ф6�Xɔ�[:�[��h�(�MQ���&gt;���;l[[��VN�hK/][�!�mJC

.... and so on

我还有另一个功能,允许用户下载我直接存储在数据库中的 PDF 作为 base64 中的字符串。这些是我的应用程序生成的 PDF,而且相当小,所以我将它们直接存储在数据库中,而不是我存储在 AWS S3 中的那些是用户提交的,大小可以是几 MB(我的数据库中的只是一个几KB)

我用来处理我的 base64 pdf 并向用户提供可下载链接的功能如下所示

export const makePdfUrlFromBase64 = (base64) => {
    const binaryImg = atob(base64);
    const binaryImgLength = binaryImg.length;
    const arrayBuffer = new ArrayBuffer(binaryImgLength);
    const uInt8Array = new Uint8Array(arrayBuffer);

    for (let i = 0;  i < binaryImgLength;  i++) {
        uInt8Array[i] = binaryImg.charCodeAt(i);
    }
    const outputBlob = new Blob([uInt8Array], {type: 'application/pdf'});
    return URL.createObjectURL(outputBlob)
}

但是,当我尝试将此函数应用于从 AWS 返回的数据时,我收到此错误:

DOMException: Failed to execute 'atob' on 'Window': The string to be decoded contains characters outside of the Latin1 range.

那么我在这里从 AWS 获得什么样的二进制数据编码?

注意:我可以通过在 img 标记中传递 src 来使用此二进制数据呈现图像,如下所示: <img src={data:${res.headers['Content-Type']};base64,${res.data}} />

这是我最大的暗示,这是某种形式的 base64?

请!如果有人知道我如何在这里实现我的目标,我全神贯注!目标是能够提示用户下载我在 S3 URI 中拥有的资源。我可以链接到它,他们可以在浏览器中打开它,然后手动下载,但我想强制提示。

有人知道这里返回的是什么类型的数据吗?有什么方法可以将其解析为流?缓冲区?

我曾尝试使用 JSON 对其进行字符串化或将其作为字符串记录到控制台,此时我对所有建议持开放态度

标签: javascripthttppdfamazon-s3binary-data

解决方案


您正在进行各种不需要的转换。当您GET提出请求时,您已经拥有所需格式的数据。

const response = await fetch(attachment.fileUrl,
    headers: {Authorization: ''}}
});
const blob = await response.blob();
return URL.createObjectURL(res.data);

推荐阅读