Envoi d'une requête POST à l'aide de NSURLSession

Mise à jour: Solution trouvée. Vous pouvez le lire à la fin du post.

Je suis en train d'effectuer une requête POST à distance à l'aide de l'API REST NSURLSession. L'idée est de faire une demande auprès de deux paramètres: deviceId et textContent.

Le problème est que ces paramètres ne sont pas reconnu par le serveur. La partie serveur fonctionne correctement, car j'ai envoyé un courrier en utilisant le FACTEUR de Google Chrome et cela a fonctionné parfaitement.

C'est le code que j'utilise actuellement:

NSString *deviceID = [[NSUserDefaults standardUserDefaults] objectForKey:@"deviceID"];
NSString *textContent = @"New note";
NSString *noteDataString = [NSString stringWithFormat:@"deviceId=%@&textContent=%@", deviceID, textContent];

NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.HTTPAdditionalHeaders = @{
                                               @"api-key"       : @"API_KEY",
                                               @"Content-Type"  : @"application/json"
                                               };
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
NSURL *url = [NSURL URLWithString:@"http://url_to_manage_post_requests"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPBody = [noteDataString dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPMethod = @"POST";
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    //The server answers with an error because it doesn't receive the params
}];
[postDataTask resume];

J'ai essayé la même procédure avec un NSURLSessionUploadTask:

//...
NSURL *url = [NSURL URLWithString:@"http://url_to_manage_post_requests"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:[noteDataString dataUsingEncoding:NSUTF8StringEncoding] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    //The server answers with an error because it doesn't receive the params
}];
[uploadTask resume];

Des idées?

Solution

Le problème avec mon approche est que j'ai été l'envoi de la mauvaise Content-Type - tête avec toutes mes demandes. Donc, le seul changement nécessaire pour que le code fonctionne correctement est de supprimer la Content-Type = application/json en-tête HTTP. Donc le bon code serait celui-ci:

NSString *deviceID = [[NSUserDefaults standardUserDefaults] objectForKey:@"deviceID"];
NSString *textContent = @"New note";
NSString *noteDataString = [NSString stringWithFormat:@"deviceId=%@&textContent=%@", deviceID, textContent];

NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.HTTPAdditionalHeaders = @{
                                               @"api-key"       : @"API_KEY"
                                               };
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];
NSURL *url = [NSURL URLWithString:@"http://url_to_manage_post_requests"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPBody = [noteDataString dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPMethod = @"POST";
NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    //The server answers with an error because it doesn't receive the params
}];
[postDataTask resume];

D'envoyer des images avec d'autres paramètres

Si vous avez besoin d'afficher des images avec d'autres paramètres à l'aide de NSURLSession ici vous avez un exemple:

NSString *deviceID = [[NSUserDefaults standardUserDefaults] objectForKey:@"deviceID"];
NSString *textContent = @"This is a new note";
//Build the request body
NSString *boundary = @"SportuondoFormBoundary";
NSMutableData *body = [NSMutableData data];
//Body part for "deviceId" parameter. This is a string.
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", @"deviceId"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@\r\n", deviceID] dataUsingEncoding:NSUTF8StringEncoding]];
//Body part for "textContent" parameter. This is a string.
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", @"textContent"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@\r\n", textContent] dataUsingEncoding:NSUTF8StringEncoding]];
//Body part for the attachament. This is an image.
NSData *imageData = UIImageJPEGRepresentation([UIImage imageNamed:@"ranking"], 0.6);
if (imageData) {
[body appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"image.jpg\"\r\n", @"image"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Type: image/jpeg\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:imageData];
[body appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
}
[body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
//Setup the session
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfiguration.HTTPAdditionalHeaders = @{
@"api-key"       : @"55e76dc4bbae25b066cb",
@"Accept"        : @"application/json",
@"Content-Type"  : [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]
};
//Create the session
//We can use the delegate to track upload progress
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:nil];
//Data uploading task. We could use NSURLSessionUploadTask instead of NSURLSessionDataTask if we needed to support uploads in the background
NSURL *url = [NSURL URLWithString:@"URL_TO_UPLOAD_TO"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
request.HTTPBody = body;
NSURLSessionDataTask *uploadTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
//Process the response
}];
[uploadTask resume];
  • Tangentiellement, si vous utilisez seulement un NSURLSessionUploadTask, il publie des données brutes de votre serveur. Qui, vous pouvez toujours travailler avec, par exemple, via file_get_contents('php://input') in PHP -- mais vous devez inclure d'autres données dans les en-têtes.
  • Belle solution! Utilisé pour créer mon propre formulaire multipart compositeur.
  • J'avais une autre question, mais le tip-off concernant Content-Type était tout ce que j'avais besoin de comprendre les choses. Merci!
  • Pour certaines raisons, ça a arrêté de travailler pour moi, tout d'un coup sur la dernière version ios8. Il a travaillé comme un champion pour un an, puis tout d'un coup je reçois des requêtes mal formées sur le serveur et je ne suis pas sûr de ce changement dans la façon dont je compose à la demande. Je ne pouvais pas reproduire le problème, les utilisateurs avaient avec XCode simulateur, puis j'ai mis à jour de XCode 6.3.1 et kablam je suis vissé juste en train de me tuer. Impossible de savoir pourquoi mon serveur est tellement malheureux avec les demandes.
  • Merci de donner la réponse avec le code pour l'envoi d'une image avec des paramètres. L'envoi de l'image a fonctionné à merveille! Comme pour les paramètres, j'ai dû ajouter à l'URL de leur faire le travail.
  • Je suis votre exemple, et pour envoyer de multiples champs de l'image. Je vous envoie le format d'image PNG. En cours d'exécution dans un problème, merci de m'aider à le résoudre. J'ai un django basée sur serveur et renvoie une erreur pour l'image. "Les données présentées n'était pas un fichier. Vérifiez le type de codage sur la forme."
  • [corps appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n", @"image_file"] dataUsingEncoding:NSUTF8StringEncoding]]; [corps appendData:[@"Content-Type: image/png\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; [corps appendData:pageData]; [corps appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
  • une boucle de commande comme ci-dessous travail "curl-i-F "page_index=0" -F "p=1" -F "image_file=@./FullSizeRender.png gmm.com:5000/p/images HTTP/1.1"
  • votre solution, y compris l'API était EXACTEMENT ce que je cherchais, merci beaucoup!!!!
  • La "solution" à la question devrait être ajouté comme une réponse 🙂
  • est-il nécessaire d'ajouter des en-têtes supplémentaires ?
  • Ajout de toutes les chaînes et seulement la conversion de données lorsque la chaîne est composée également de travail, tout en le rendant un peu plus lisible 🙂
  • S'il vous plaît ne mettez pas de réponses à votre question, si vous avez un poste à titre de réponse, plutôt que de le mettre là. Veuillez vous référer à cette la poste sur Meta

InformationsquelleAutor Sendoa | 2013-09-30