2016-11-05 101 views
2

我試圖重新創建在React Native中上傳用戶提交圖片的Heroku example,但不斷收到來自AWS的400個錯誤。從ReactNative(iOS)直接發佈到AWS S3,帶有簽名請求

圖像來自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); 
    }); 
}); 

回答

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,在那裏一個簡單的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); 
}; 
相關問題