【问题标题】:AWS S3 multipart / uploadPart silent fail from browser JS SDKAWS S3 multipart / uploadPart 静默失败,来自浏览器 JS SDK
【发布时间】:2018-03-08 09:07:04
【问题描述】:

我正在尝试使用 JS SDK 从浏览器上传多部分 s3。我对createMultipartUpload 没有任何问题,但是我没有从uploadPart 得到任何数据。我无法调用 completeMultipartUpload,因为我没有取回任何 eTag。我只得到对象的 $response 部分,它表示 200 状态,并且我传递的所有参数都已定义和正确的数据类型。我看不到存储桶中的任何零件,尽管我不知道它们是否会进入我无法访问的特殊“零件”位置。

这是我的代码:

    const createParams = {
      Bucket,
      Key: `${uuid()}.${getExtension(file.type)}`,
      ContentType: file.type,
      ContentDisposition: 'attachment'
    }
    return s3.createMultipartUpload(createParams).promise()
    .then(result => {
      console.log(result);
      console.log('chunking...')
      let chunkArr = chunker(file);
      let chunkMap = Promise.map(chunkArr, (chunk, index) => {
        const chunkParams = {
          Body: chunk,
          Bucket: result.Bucket,
          Key: result.Key,
          PartNumber: index + 1,
          UploadId: result.UploadId,
          ContentLength: chunk.size
        }
        console.log(chunkParams)
        return s3.uploadPart(chunkParams).promise();
      });
      return Promise.all(chunkMap);
    })
    .then(result => {
      console.log(result);
      return Promise.resolve(true)
      // let stopParams = {
      //
      // }
      // return s3.completeMultipartUpload(stopParams).promise();
    })
    .catch(err => {
      throw err;
      return Promise.reject(err);
    });

s3 实例如下所示:

import AWS from 'aws-sdk';
AWS.config.setPromisesDependency(Promise);

const s3 = new AWS.S3({
    apiVersion: '2006-03-01',
    accessKeyId: credentials.credentials.AccessKeyId,
    secretAccessKey: credentials.credentials.SecretAccessKey,
    sessionToken: credentials.credentials.SessionToken,
    sslEnabled: true,
    s3ForcePathStyle: true,
    httpOptions: {
      xhrAsync: true,
      xhrWithCredentials: true
    }
  })

chunker 函数如下所示:

  const chunkFile = (file) => {
    console.log(typeof(file));
    const fileSize = file.size;
    const chunkSize = 5242881; // bytes
    let offset = 0;
    let chunkArr = [];

    const chunkReaderBlock = (_offset, _file) => {
      console.log(_offset);

      if (_offset >= fileSize) {
        console.log("Done reading file");
        return chunkArr;
      }

      let blob = _file.slice(_offset, chunkSize + _offset);
      console.log(blob);
      console.log(typeof(blob));
      chunkArr.push(blob);
      return chunkReaderBlock(chunkSize + _offset, _file);
    }

    return chunkReaderBlock(offset, file);
  }

我返回的响应对象如下所示:

    (2)[{…}, {…}] 

0: {
  $response: Response
}

1: $response: Response 
  cfId: undefined 
  data: {
    $response: Response
  }
  error: null 
  extendedRequestId: undefined 
  httpResponse: HttpResponse 
    body: Uint8Array[] 
    headers: {}
    statusCode: 200 
    statusMessage: "OK"
    stream: EventEmitter {
      _events: {…},
      _maxListeners: undefined,
      statusCode: 200,
      headers: {…}
    }
    streaming: false 
    _abortCallback: ƒ callNextListener(err) __proto__: Object 
    maxRedirects: 10 
    maxRetries: 3 
    redirectCount: 0 
    request: Request {
      domain: undefined,
      service: f… s.constructor,
      operation: "uploadPart",
      params: {…},
      httpRequest: HttpRequest,
      …
    }
  retryCount: 0 
  __proto__: Object 
  __proto__: Object 
 length: 2 
__proto__: Array(0)

有什么想法吗?这是在 React 中,我的测试文件是 9.xx MB。我也尝试了回调,一次上传一个部分,得到了同样的结果。

【问题讨论】:

标签: javascript amazon-s3


【解决方案1】:

在跨域上下文中,您需要在存储桶的 CORS 配置中使用它:

<ExposeHeader>ETag</ExposeHeader>

ExposeHeader — 标识客户将能够从他们的应用程序(例如,从 JavaScript XMLHttpRequest 对象)访问的响应标头。"

https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html

为了澄清这里发生了什么,CORS 不是一种访问限制机制——它是一种允许浏览器执行某些操作的机制,否则它认为可能不是用户想要发生的事情。它告诉浏览器允许 JavaScript 执行和查看原本不允许执行的操作。

来自 Mozilla CORS 文档:

默认情况下,只公开 6 个简单的响应头:

Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma

如果您希望客户端能够访问其他标头,则必须使用 Access-Control-Expose-Headers 标头列出它们。

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers

在 S3 中,设置Access-Control-Expose-Headers 响应标头的方式是通过配置&lt;ExposeHeaders&gt;(上图)。否则,JavaScript 看不到它们。


我看不到存储桶中的任何零件,尽管我不知道它们是否会进入我无法访问的特殊“零件”位置。

他们是。使用listMultipartUploads 查找放弃的上传,使用abortMultipartUploads 删除部分上传并为您上传的部分释放分配的存储空间。否则,您未完成的上传将无限期地逗留,并且您将被收取存储部件的费用。此外,您可以创建一个bucket lifecycle policy,以便在这么多天后自动处理它们——这几乎总是一个好主意。

【讨论】:

    猜你喜欢
    • 2022-11-03
    • 2019-07-19
    • 2021-06-25
    • 2016-10-08
    • 2012-10-22
    • 1970-01-01
    • 2021-12-31
    • 2019-12-11
    • 1970-01-01
    相关资源
    最近更新 更多