2015-04-30 3 views
8

[WARNUNG]
Wie ich, dass diese Frage bin sehen wird immer bemerkt mehr, als es sollte, ich möchte Ihnen sagen, nicht von der verwenden folgender Code
Zu der Zeit, als ich die Frage stellte, hatte Swift weniger als ein Jahr, bewegte sich schnell, die meisten Bibliotheken waren nicht Swift-freundlich und instabil. Ich empfehle dringend, dass Sie versuchen, Alamofire oder eine andere Bibliothek für diese Art von Aufgabe zu verwenden. Aber tu es nicht selbst.
[/ WARNUNG]ein Bild und Parameter mit multipart/form-data in Swift Hochladen

ich ein Bild auf einen Drupal Endpunkt hochladen möchten.

Das Problem, das ich habe, ist, dass ich eine HTTP 200 OK-Antwort mit Text/HTML-Inhaltstyp erhalte. In der HTML-Antwort gibt es eine klare Nachricht, dass der Knoten korrekt erstellt wurde. Aber auf der Serverseite ist das Bild nicht mit dem Knoten verknüpft.

Ich erwarte auch nicht text/html, sondern application/json, wie ich es im Accept-Header angeben.

Es funktioniert bereits in der Android App mit Android Rest Template. Hier ist der Code als Referenz:

String url = getUrl("node/{info_id}/attach_file"); 

HttpHeaders headers = new HttpHeaders(); 
headers.setContentType(MediaType.MULTIPART_FORM_DATA); 

if (user.isLoggedIn()) { 
    headers.add(user.getSessionName(), user.getSessionId()); 
    headers.add("X-CSRF-Token", user.getToken()); 
    headers.add("Cookie", user.getSessionName() + "=" + user.getSessionId()); 
} 

MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>(); 

parts.add("files[field_mobileinfo_image]", 
     new FileSystemResource(info.getImageUri())); 
parts.add("field_name", "field_mobileinfo_image"); 

HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(parts, headers); 
return getRestTemplate().exchange(url, HttpMethod.POST, request, Void.class, info.getId()).getBody(); 

Ich weiß, ich habe nicht die Antwort in Android überprüfen (Void.class), aber alles funktioniert und das Bild wird mit dem Knoten auf der Serverseite angebracht.

Jetzt auf iOS in Swift habe ich mehrere Dinge ausprobiert.

Mit AFNetworking:

func upload(mobileInfo: MobileInfo) { 
    let user = userService.load() 
    let url = Config.buildUrl("") 

    let manager = AFHTTPRequestOperationManager(baseURL: NSURL(string:url)!) 
    let serializer = AFHTTPRequestSerializer() 
    serializer.setValue(user.sessionId, forHTTPHeaderField: user.sessionName) 
    serializer.setValue(user.token, forHTTPHeaderField: "X-CSRF-Token") 
    serializer.setValue("\(user.sessionName)=\(user.sessionId)", forHTTPHeaderField: "Cookie") 
    manager.requestSerializer = serializer 

    manager.responseSerializer.acceptableContentTypes.removeAll(keepCapacity: false) 
    manager.responseSerializer.acceptableContentTypes.insert("application/json") 

    let imageData = UIImageJPEGRepresentation(mobileInfo.image, 0.3)  
    manager.POST("/node/\(mobileInfo.id)/attach_file", parameters: nil, constructingBodyWithBlock: { (formData) -> Void in 
     formData.appendPartWithFileData(
      imageData, 
      name: "files[field_mobileinfo_image]", 
      fileName: "field_mobileinfo_image", 
      mimeType: "image/jpeg") 
     formData.appendPartWithFormData("field_mobileinfo_image".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true), name: "field_name") 
    }, 
    success: { (operation, data) -> Void in 
     println(data) 
    }) { (operation, error) -> Void in 
     println(error) 
    } 
} 

manuell mit Informationen aus anderen Stackoverflow Fragen packte:

func upload2(mobileInfo: MobileInfo) { 
    let user = userService.load() 
    let imageData = UIImageJPEGRepresentation(mobileInfo.image, 0.3) 
    let url = NSURL(string:Config.buildUrl("/node/\(mobileInfo.id)/attach_file"))! 
    println(url) 
    var request = NSMutableURLRequest(URL: url) 
    var session = NSURLSession.sharedSession() 
    request.HTTPMethod = "POST" 
    var boundary = "---------------------------14737809831466499882746641449" 
    var contentType = "multipart/form-data; boundary=\(boundary)" 
    println(contentType) 
    request.addValue(contentType, forHTTPHeaderField: "Content-Type") 
    request.addValue("application/json", forHTTPHeaderField: "Accept") 
    request.addValue("\(user.sessionName)=\(user.sessionId)", forHTTPHeaderField: "Cookie") 
    request.addValue(user.sessionId, forHTTPHeaderField: user.sessionName) 
    request.addValue(user.token, forHTTPHeaderField: "X-CSRF-Token") 

    println(request.allHTTPHeaderFields) 

    var body = NSMutableData() 

    body.appendData("\r\n--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
    body.appendData("Content-Disposition: form-data; name=\"field_name\"\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
    body.appendData("field_mobileinfo_image".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!) 

    body.appendData("\r\n--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
    body.appendData("Content-Disposition: form-data; name=\"files[field_mobileinfo_image]\"; filename=\"img.jpg\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
    body.appendData("Content-Type: application/octet-stream\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
    body.appendData(imageData) 
    body.appendData("\r\n--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 


    var returnData = NSURLConnection.sendSynchronousRequest(request, returningResponse: nil, error: nil) 

    var returnString = NSString(data: returnData!, encoding: NSUTF8StringEncoding) 

    println("returnString \(returnString)") 
} 

Mit SRWebClient:

func upload3(mobileInfo: MobileInfo) { 
    let user = userService.load() 
    let imageData:NSData = NSData(data: UIImageJPEGRepresentation(mobileInfo.image, 0.3)) 
    SRWebClient.POST("http://master.test.lesfrontaliers.lu/node/\(mobileInfo.id)/attach_file") 
     .headers(["Accept": "application/json", 
      user.sessionName: user.sessionId, 
      "X-CSRF-Token": user.token, 
      "Cookie": "\(user.sessionName)=\(user.sessionId)"]) 
     .data(imageData, fieldName:"files[field_mobileinfo_image]", data:["field_name":"field_mobileinfo_image"]) 
     .send({ (response: AnyObject!, status: Int) -> Void in 
      println(status) 
      println(response) 
     },failure:{(error:NSError!) -> Void in 
      println(error) 
     }) 
} 

Bitte rette mich! ;-) Ich habe so viele Dinge ausprobiert, dass es funktioniert, dass ich nicht mehr sehen kann, wenn ich etwas falsch mache. Es scheint in Ordnung für mich. Der einzige Unterschied, den ich sehen kann, ist, dass ich das Bild nicht auf dem Dateisystem ablege, sondern direkt die binären Daten sende, die am Ende dasselbe sind.Hier

ist ein Bild des Antrags in Postman erstellt (Arbeits- und Empfangen von json)

Postman

[EDIT] Wenn es kann hier jemand helfen den richtigen Code des falschen Teil der ist über manuelle Anfrage:

var body = NSMutableData() 

body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
body.appendData("Content-Disposition: form-data; name=\"field_name\"\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
body.appendData("field_mobileinfo_image\r\n".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!) 

body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
body.appendData("Content-Disposition: form-data; name=\"files[field_mobileinfo_image]\"; filename=\"img.jpg\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
body.appendData("Content-Type: image/jpeg\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
body.appendData(imageData) 
body.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 

body.appendData("--\(boundary)--\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 

request.HTTPBody = body 
+0

wie ist das getan, wenn ich Post-Parameter auch senden muss? http://stackoverflow.com/questions/30006290/uploading-image-in-swift-with-multiple-parameters – Tyler

+0

Warum geben Sie 'image.jpeg' an, wenn Ihre Datei die Erweiterung' png' hat? –

+0

Ich frage mich auch immer, was die zwei zusätzlichen, führenden Bindestriche vor dem Grenzstring ('--') sind. –

Antwort

2

Sie wissen nicht, ob dies für funktioniert, was Sie versuchen zu tun, aber wir verwenden diese Bilder hochladen, der wesentliche Unterschied ist filename und Content-type zu verwenden:

[self appendBody:body data:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\".jpg\"\r\n", key]]; 

[self appendBody:body data:@"Content-Type: image/jpeg\r\n\r\n"]; 
[body appendData:imageData]; 
+1

OMG. Ich danke dir sehr. Sie bringen mich auf die richtige Spur. Ich weiß nicht, warum ich so viel Mist mit der "manuellen" Anfrage gemacht habe, aber wenn Sie auf meine Frage schauen, ist das völlig falsch (keine letzte Grenze usw.) und obendrein ... der Körper ist nicht auf die Anfrage eingestellt . Das Hinzufügen des Content-Typs image/jpeg gab mir schließlich einen Fehler vom Server anstelle des falschen HTTP 200. Was mich stört ist, dass AFNetworking und SRWebClient nicht funktioniert haben, obwohl sie stark ausgelastet sind. – florian

+0

Super, froh, dass es funktioniert hat! Ja, Networking scheint immer schmerzhafter zu sein, als es sein sollte. – rmp

1

Für swift 2.0 JSON Anfrage und PHP-Code: - (Manuell)

let imageData = UIImageJPEGRepresentation(userImage, 0.3) 
    let url:NSURL = NSURL(string: serverURL!)! // Give ur request URL 
    let request = NSMutableURLRequest(URL: url) 
    request.HTTPMethod = "POST" 
    let boundary = "---------------------------14737809831466499882746641449" 
    let contentType = "multipart/form-data; boundary=\(boundary)" 
    request.addValue(contentType, forHTTPHeaderField: "Content-Type") 
    let body = NSMutableData() 
    body.appendData("--\(boundary)\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
    body.appendData("Content-Disposition: form-data; name=\"userfile\"; filename=\"img.jpg\"\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
    body.appendData("Content-Type: image/jpeg\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
    body.appendData("Content-Transfer-Encoding: binary\r\n\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
    body.appendData(imageData!) 
    body.appendData("\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
    body.appendData("--\(boundary)--\r\n".dataUsingEncoding(NSUTF8StringEncoding)!) 
    request.HTTPBody = body 

PHP-Code: -

<?php 

//http://192.168.1.154/Contact/uploadImgwebservice.php 

//print the username and password using php 

echo $_POST[‘username’]; 

echo $_POST[‘password’]; 

//upload your file 

$uploaddir = ‘./uploads/’; 

$file = basename($_FILES[‘userfile’][‘name’]); 

$uploadfile = $uploaddir . $file; 

if (move_uploaded_file($_FILES[‘userfile’][‘tmp_name’], $uploadfile)) { 

    echo “http://192.168.1.154/Contact/uploads/{$file}”; 

} 

?>