【问题标题】:Direct post to AWS S3 from ReactNative (iOS) with signed request使用签名请求从 React Native (iOS) 直接发布到 AWS S3
【发布时间】:2017-03-19 13:00:05
【问题描述】:

我正在尝试重新创建在 React Native 中上传用户提交的图像的 Heroku example,但不断收到来自 AWS 的 400 错误。

图片来自 iOS 相机胶卷。我有图像的 uri 和图像的 base64 编码版本。 MIME 类型为image/jpeg。到目前为止,我已经按照 Heroku 的说明设置了所有内容,但是在制作我发送正确形状的文件时遇到了麻烦。我在下面添加了我的代码以进行澄清。

我正在使用react-native-image-picker 从相机胶卷中选择图像

客户端代码

module.exports = React.createClass({
...

openPhotos() { // called on a button press, opens camera roll
    ImagePicker.showImagePicker(options, (response) => {
      if (response.didCancel) return;
      if (response.error) return Alert.alert('ImagePicker Error: ', response.error);
      this.getSignedRequest(response);
    });
  },
getSignedRequest(pickerResp) {
  // image uri IS pickerResp.uri AS IS `data:image/jpg;base64,${pickerResp.data}`
  var file = {
    uri: pickerResp.uri, // ALSO WORKS `data:image/jpg;base64,${pickerResp.data}`,
    name: `${this.props.email}.jpg`,
    type: 'image/jpeg'
  };
  var body = new FormData();
  body.append('file', file);

  fetch(`${api.TEST_API}sign-s3?file-name=${file.name}.jpg&file-type=${file.type}`, {
    method: "GET"
  }).then(response => response.json()).then(data => {
    Alert.alert("GOT SIGNED REQUEST",data.url);
    fetch(data.signedRequest, { method: 'put', body: body }).then(resp => resp.json()).then(data => {
      this.setState({uploadedFile: true});
      this.props.toSignup();
    }).catch(err => Alert.alert("Server Error", "Could not upload profile photo."))
  }).catch(err => {
    Alert.alert('S3 Signed Request Error',"Look at the Logs");
    console.log(err);
  })
},

...
};

服务器端代码

AWS NPM 包:[aws-sdk]

// get signature to upload client side to s3
apiRouter.get('/sign-s3', function(req, res) {
  console.log('signing s3')
  const s3 = new aws.S3(); // automatically loads key and secret
  const fileName = req.query['file-name'];
  const fileType = req.query['file-type'];
  const s3Params = {
    Bucket: S3_BUCKET,
    Key: fileName,
    Expires: 60,
    ContentType: fileType,
    ACL: 'public-read'
  };

  s3.getSignedUrl('putObject', s3Params, (err, data) => {
    if(err) return console.log(err)
    const returnData = {
      signedRequest: data,
      url: `https://${S3_BUCKET}.s3.amazonaws.com/${fileName}`
    };
    console.log(returnData)
    res.json(returnData);
  });
});

【问题讨论】:

    标签: ios node.js heroku amazon-s3 react-native


    【解决方案1】:

    fetch(`${api.TEST_API}sign-s3?file-name=${file.name}.jpg&file-type=${file.type}

    这里的获取请求是在所描述的文件名末尾添加一个额外的.jpg,因此当您尝试上传到 S3 时,它会被拒绝,因为有效负载与先前的请求不匹配。此外,Heroku 建议的 XMLHttpRequest 可以很好地处理您拥有的文件结构,但可以使用 base64 数据(如下)。

    var file = {
      uri: `data:image/jpg;base64,${pickerResp.data}`, //pickerResp.uri,
      type: 'image/jpeg',
      name: `${this.props.email}.jpg`,
    };
    

    以下 XML HTTP 请求会将图像以其编码形式发送到 S3,在 S3 中,一个简单的 GET 请求或图像 src 属性可以访问该文件。

    function uploadFile(file, signedRequest, url, cb) {
      const xhr = new XMLHttpRequest();
      xhr.open('PUT', signedRequest);
      xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
          if(xhr.status === 200) {
            cb()
          } else {
            alert('Could not upload file.');
          }
        }
      };
      xhr.send(file);
    };
    

    【讨论】:

      猜你喜欢
      • 2020-03-26
      • 2017-12-26
      • 2018-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多