2015-06-09 16 views
5

Desidero caricare immagini dalla mia app al server S3. Ho calcolato tutti i dati e i codici (testato usando curl sul computer) ma non riesco a capire come chiamare correttamente 'fetch'. Ricevo risposta:Immagine di caricamento nativa di React su amazons s3

'Almeno una delle pre-condizioni specificate non è stata mantenuta. Condizione: POST Bucket deve essere di tipo enclosure-multipart/form-data '

Come posso ricreare i dati di modulo in recupero reagenti nativi? Non ci sono FormData a cui posso aggiungere e quindi inviarlo come nell'esempio di fetch.

MODIFICA: Grazie @ philipp-von-weitershausen, greare di aver aggiunto questa funzione. Tuttavia ho qualche problema chiamarlo. Ricevo "Tipo BodyInit non supportato". Trovato perché in fetch.js: "support.formData" restituisce false. Cosa mi manca quando chiamo fetch?

mio esempio di codice:

var form = new FormData(); 
form.append("FormData", true) 
form.append("name", this.state.invoiceNumber) 
form.append("key", this.state.invoiceNumber) 
form.append("Content-Type", "image/png") 
form.append('file', this.props.uri) 
//alert(FormData.prototype.isPrototypeOf(form)) 

    fetch(amazon_url,{body: form,mode: "FormData", method: "post", headers: {"Content-Type": "multipart/FormData"}}) 
      .then((response) => response.json()) 
      .catch((error) => { 
      alert("ERROR " + error) 
      }) 
      .then((responseData) => { 
      alert("Succes "+ responseData) 
      }) 
      .done(); 
+0

Hai un esempio del codice finale di lavoro per questo? Anch'io sto avendo problemi. –

+0

In effetti, hai un esempio di solo poter pubblicare le variabili del modulo (senza le immagini - visto che la prossima build RN aggiunge il supporto per le immagini). –

+0

[react-native-fetch-blob] (https://github.com/wkh237/react-native-fetch-blob) può farlo per te. – Xeijp

risposta

7

Alcune persone hanno chiesto, quindi sto postando come l'ho fatto. È stato fatto molto tempo fa, quindi se avete commenti o qualcosa di veramente brutto, sono aperto alla critica;) La foto è in lettura da cameraRetro e archiviata in 'latestPhoto'.

Caricamento foto da S3 server:

Fase 1: Genera dati:

_addTextParam() { 
    var textParams = this.state.textParams; 
    s3_upload_id = this.makeid() 
    textParams.push({ name: "key", value: this.state.upload_path + s3_upload_id + '/' + this.state.att_name + ".jpg" }) 
    textParams.push({ name: "AWSAccessKeyId", value: this.state.key }) 
    textParams.push({ name: "acl", value: "public-read" }) 
    textParams.push({ name: "success_action_status", value: "201" }) 
    textParams.push({ name: "policy", value: this.state.policy }) 
    textParams.push({ name: "signature", value: this.state.signature }) 
    textParams.push({ name: "Content-Type", value: "image/jpeg" }) 

    this.setState({ textParams: textParams }); 
    } 

Fase 2: Invia dati:

_send() { 

    this._addTextParam() 
    var xhr = new XMLHttpRequest(); 
    xhr.open('POST', "http://" + this.state.fs_domain + "." + this.state.server); 
    xhr.onload =() => { 
     this.setState({ isUploading: false }); 
     if (xhr.status !== 201) { 
     AlertIOS.alert( 
      'Upload failed', 
      'Expected HTTP 200 OK response, got ' + xhr.status + "/" + xhr.responseText 
     ); 
     return; 
     } 

     if (!xhr.responseText) { 
     AlertIOS.alert(
      'Upload failed', 
      'No response payload.' 
     ); 
     return; 
     } 
     var index = xhr.responseText.indexOf("http://" + this.state.fs_domain + "." + this.state.server); 
     if (index === -1) { 
     AlertIOS.alert(
      'Upload failed', 
      'Invalid response payload.' 
     ); 
     return; 
     } 
     var url = xhr.responseText.slice(index).split('\n')[0]; 
     this.state.s3_file_id = xhr.responseText.split('Tag>"')[1].split('"')[0] 
     this.state.s3_file_path = xhr.responseText.split('Location>')[1].split('<')[0] 
     this.setState({ isUploading: false }); 
     RCTDeviceEventEmitter.emit('Uploaded') 

    }; 
    var formdata = new FormData(); 

    this.state.textParams.forEach((param) => { 
     formdata.append(param.name, param.value) 
     } 
    ); 

    formdata.append('file', {...this.state.latestPhoto, name: (this.state.att_name+".jpg") }); 

    xhr.send(formdata); 
    this.setState({ isUploading: true }); 

    }, 
+0

E 'latestPhoto' è binario? Mi chiedo solo come funziona. –

+0

E come hai generato la firma? I moduli che ho trovato online dipendono da alcune funzionalità del nodo come 'http' e' fs'. –

+0

@HarryMoreno La foto è caricata da: [CameraRoll] (http://facebook.github.io/react-native/docs/cameraroll.html # content) E la firma I recupera dalla nostra applicazione principale scritta in Ruby on Rails. Ma penso che potresti essere in grado di ricrearlo in base ai documenti AWS. –

5

multipart/form-data supporto per React nativo (tramite l'XHR FormData API) per carichi misti (stringhe JS + immagine payload) è in preparazione. Dovrebbe atterrare presto a GitHub.

+2

aaa e atterrato: https://github.com/facebook/react-native/commit/f4bf80f3ea3b7ed6aee8b068ec1a289e0965eb5e –

+0

Grande !! Vedo che cambi anche qualcosa nel metodo di chiamare fetch? Ha smesso di funzionare o mostra un errore: Undiefiened non è una funzione (valutazione di RCTDataMenager.queryData ('http', {metodo: metodo, url: url, dati: dati, intestazioni: intestazioni}). Qualche possibilità sul suggerimento rapido che cosa è cambiato? –

+0

Nevermind, ho avuto due versioni di react-native e non mi piacevano in questa cartella ... –

2

@ Michał Zubrzycki Grazie, il codice per il caricamento di foto ha funzionato per me con piccoli cambiamenti.

var photo = { 
    uri: user.profilePicture, 
    type: 'image/jpeg', 
    name: 'photo.jpg', 
}; 
var form = new FormData(); 
form.append("ProfilePicture", photo); 
fetch(
    Constants.API_USER + 'me/profilePicture', 
    { 
    body: form, 
    method: "PUT", 
    headers: { 
     'Content-Type': 'multipart/form-data', 
     'Authorization': 'Bearer ' + user.token 
    } 
    } 
).then((response) => response.json()) 
.catch((error) => { 
    alert("ERROR " + error) 
}) 
.then((responseData) => { 
    alert("Succes "+ responseData) 
}).done(); 
+0

Grazie questo è davvero utile! –

+0

Grazie! sei un salvagente – cipherz

1

opzioni S3:

// this.state.s3options in YourComponent 
{ 
    "url": "https://yourapp.s3.eu-central-1.amazonaws.com", 
    "fields": { 
    "key": "cache/22d65141b48c5c44eaf93a0f6b0abc30.jpeg", 
    "policy": "eyJleHBpcm...1VDE0Mzc1OVoifV19", 
    "x-amz-credential": "AK...25/eu-central-1/s3/aws4_request", 
    "x-amz-algorithm": "AWS4-HMAC-SHA256", 
    "x-amz-date": "20161125T143759Z", 
    "x-amz-signature": "87863c360...b9b304bfe650" 
    } 
} 

Componente:

class YourComponent extends Component { 
    // ... 

    // fileSource looks like: {uri: "content://media/external/images/media/13", isStatic: true} 
    async uploadFileToS3(fileSource) { 
    try { 
     var formData = new FormData(); 
     // Prepare the formData by the S3 options 
     Object.keys(this.state.s3options.fields).forEach((key) => { 
     formData.append(key, this.state.s3options.fields[key]); 
     }); 
     formData.append('file', { 
     uri: fileSource.uri, 
     type: 'image/jpeg', 
     }); 
     formData.append('Content-Type', 'image/jpeg') 

     var request = new XMLHttpRequest(); 
     request.onload = function(e) { 
     if (e.target.status === 204) { 
      // Result in e.target.responseHeaders.Location 
      this.setState({avatarSourceRemote: {uri: e.target.responseHeaders.Location}}) 
     } 
     }.bind(this) 
     request.open('POST', this.state.s3options.url, true); 
     request.setRequestHeader('Content-type', 'multipart/form-data'); 
     request.send(formData); 
    } catch(error) { 
     console.error(error); 
    } 
    } 

    // Example display the uploaded image 
    render() { 
    if (this.state.avatarSourceRemote) { 
     return (
     <Image source={this.state.avatarSourceRemote} style={{width: 100, height: 100}} /> 
    ); 
    } else { 
     return (
     <Text>No Image</Text> 
    ); 
    } 
    } 
}