[ATTENZIONE]
Come sto vedendo che la questione è farsi notare più di quanto dovrebbe, voglio dirti di non utilizzare nessuna delle codice seguente
All'epoca in cui ponevo la domanda, Swift aveva meno di un anno, si muoveva velocemente, la maggior parte delle biblioteche non erano veloci e instabili. Si consiglia vivamente di provare a utilizzare Alamofire o un'altra libreria per questo tipo di attività. Ma non farlo da solo.
[/ ATTENZIONE]Caricamento un'immagine e parametri con multipart/form-data a Swift
voglio caricare un'immagine da un endpoint Drupal.
Il problema è che ricevo una risposta HTTP 200 OK con tipo di contenuto text/html. Nella risposta HTML, c'è un chiaro messaggio che il nodo è stato creato correttamente. Ma sul lato server l'immagine non è associata al nodo.
Inoltre non mi aspetto testo/html ma application/json come lo specifico nell'intestazione Accept.
Funziona già nell'app per Android utilizzando Android Rest Template. Ecco il codice di riferimento:
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();
So che non controllo la risposta in Android (Void.class
), ma tutto funziona bene e l'immagine è allegata al nodo sul lato server.
Ora su iOS in Swift ho provato più cose.
Con 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)
}
}
manualmente con le informazioni afferrato da altre domande StackOverflow:
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)")
}
Con 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)
})
}
Per favore salvami! ;-) Ho provato così tante cose per farlo funzionare che non riesco a vedere più se sto facendo qualcosa di sbagliato. Sembra ok per me. L'unica differenza che posso vedere è che non sto memorizzando l'immagine sul filesystem ma inviando direttamente i dati binari che è la stessa cosa alla fine.
Ecco un'immagine della richiesta creata in Postman (di lavoro e ricevere JSON)
[EDIT] se può aiutare qualcuno qui è il codice corretto della parte sbagliata della sopra richiesta manuale:
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
come è questo fatto quando ho bisogno di inviare i parametri di post pure? http://stackoverflow.com/questions/30006290/uploading-image-in-swift-with-multiple-parameters – Tyler
Perché si specifica 'image.jpeg' se il file ha l'estensione' png'? –
Inoltre, mi chiedo sempre quali siano i due trattini aggiuntivi prima della stringa limite ('--'). –