2015-06-09 10 views
5

Ich möchte Bilder von meiner App auf S3-Server hochladen. Ich habe alle Daten und Codes berechnet (getestet mit Curl am Computer), aber ich kann nicht herausfinden, wie man 'fetch' richtig aufruft. Ich erhalte eine Antwort:React-native Bild hochladen zu Amazon s3

'Mindestens eine der von Ihnen angegebenen Bedingungen wurde nicht eingehalten. Bedingung: Bucket POST muss vom Typ multipart/form-data sein.

Wie kann ich Formulardaten in react-natives fetch wiederherstellen? Es gibt keine FormData, an die ich mich anhängen und dann wie in Beispielabruf senden kann.

EDIT: Danke @ philipp-von-weitershausen, dass du diese Funktion hinzugefügt hast. Jedoch habe ich einige Probleme, es zu nennen. Ich erhalte "Nicht unterstützten BodyInit-Typ". Gefunden, weil in fetch.js: "support.formData" gibt false zurück. Was vermisse ich, wenn ich anrufe?

Mein Codebeispiel:

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

Haben Sie ein Beispiel für Ihren endgültigen Arbeits Code für diese? Ich habe auch Probleme. –

+0

In der Tat, haben Sie ein Beispiel, nur in der Lage zu sein, die Formularvariablen (ohne die Bilder - zu sehen, da der nächste RN Build Bildunterstützung hinzufügt). –

+0

[reactive-native-fetch-blob] (https://github.com/wkh237/react-native-fetch-blob) kann dies für Sie tun. – Xeijp

Antwort

7

Einige Leute haben gefragt, also poste ich, wie ich es gemacht habe. Es war ruhig vor langer Zeit gemacht, also wenn Sie irgendwelche Kommentare haben oder etwas wirklich schlecht gemacht ist, bin ich offen für Kritiker;) Foto ist in der CameraRoll gelesen und in "latestPhoto" gespeichert.

Hochladen Foto S3 Server:

Schritt 1: Daten generieren:

_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 }); 
    } 

Schritt 2: Daten senden:

_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

Und 'neustePhoto' ist binär? Ich frage mich nur, wie das funktioniert. –

+0

Und wie hast du die Signatur generiert? Module, die ich online gefunden habe, hängen von einigen Knotenfunktionen wie "http" und "fs" ab. –

+0

@HarryMoreno Foto wird geladen von: [CameraRoll] (http://facebook.github.io/react-native/docs/cameraroll.html # content) Und die Signatur hole ich von unserer Hauptanwendung in Ruby on Rails geschrieben. Aber ich denke, Sie könnten es basierend auf AWS-Dokumentationen wiederherstellen. –

5

multipart/form-data Unterstützung für Native Reagieren (über die XHR FormData API) für gemischte Nutzlasten (JS Strings + Bild Nutzlasten) ist in Arbeit. Es sollte bald in GitHub landen.

+2

aaaund es gelandet: https://github.com/facebook/react-native/commit/f4bf80f3ea3b7ed6aee8b068ec1a289e0965eb5e –

+0

Großartig !! Ich sehe, Sie ändern auch etwas in der Methode des Aufrufs abrufen? Es funktioniert nicht mehr oder zeigt einen Fehler: Undiefiened ist keine Funktion (evaluieren RCTDataMenager.queryData ('http', {methode: method, url: url, daten: daten, headers: headers}). Jede Chance auf einen schnellen Tipp was hat sich geändert? –

+0

Nevermind, ich hatte zwei Versionen von reactive-native und es mochte sich nicht in diesem Ordner ... –

2

@ Michał Zubrzycki Danke, Ihr Code für ein Bild, das Hochladen arbeitete mit kleinen Änderungen für mich.

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

Danke das ist wirklich hilfreich! –

+0

Danke! Du bist ein Lebensretter – cipherz

1

S3 Optionen:

// 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" 
    } 
} 

Komponente:

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> 
    ); 
    } 
    } 
}