2016-11-05 3 views
2

사용자가 제출 한 이미지를 React Native에 업로드하는 경우 Heroku example을 다시 만들려고하지만 AWS에서 400 개의 오류가 계속 발생합니다.서명 요청을 사용하여 ReactNative (iOS)의 AWS S3에 대한 직접 게시

이미지는 iOS 카메라 롤에서 가져온 것입니다. 이미지에 대한 URI와 base64로 인코딩 된 버전이 있습니다. 마임 유형은 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 요청은 간단한 GET 요청 또는 이미지의 src 속성이 파일에 액세스 할 수 있습니다 S3로 인코딩 된 형태로 이미지를 전송합니다.

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); 
}; 
관련 문제