浏览器JS SDK中的AWS S3 multipart / uploadPart静默失败

时间:2018-03-06 02:26:54

标签: javascript amazon-s3

我正在尝试使用JS SDK从浏览器上传多部分s3。我对createMultipartUpload没有任何问题,但我没有从uploadPart返回任何数据。我无法调用completeMultipartUpload,因为我没有收到任何eTags。我只得到对象的$ 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。我也试过回调,一次上传一个部分,并得到同样的东西。

1 个答案:

答案 0 :(得分:1)

在跨源环境中,您需要在您的存储桶的CORS配置中使用此功能:

<ExposeHeader>ETag</ExposeHeader>
  

ExposeHeader - 标识客户将能够从其应用程序访问的响应标头(例如,来自JavaScript XMLHttpRequest对象)。&#34;

     

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

为了澄清这里的内容,CORS并不是一种访问限制机制 - 它是一种机制,可以让浏览器做一些其他假设可能不属于用户的事情的权限我想要发生。它告诉浏览器授予JavaScript权限并查看不允许的其他内容。

来自Mozilla CORS文档:

  

默认情况下,只显示6个简单响应标头:

     

Cache-Control Content-Language Content-Type Expires Last-Modified Pragma

     

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

     

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

在S3中,您设置Access-Control-Expose-Headers响应标头的方式是配置<ExposeHeaders>(上方)。否则,JavaScript无法看到它们。

  

我无法看到我的水桶中的任何部件,虽然我不知道他们是否会去一个特殊的部件&#34;我无法访问的地方。

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