Actualización: Solución encontrada. Puedes leerlo al final de la publicación.
Estoy tratando de realizar una solicitud POST a una API REST remota usando NSURLSession
. La idea es hacer una solicitud con dos parámetros: deviceId
y textContent
.
El problema es que el servidor no reconoce esos parámetros. La parte del servidor funciona correctamente porque envié un POST usando POSTMAN para Google Chrome y funcionó perfectamente.
Este es el código que estoy usando ahora:
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];
He intentado el mismo procedimiento con 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];
¿Algunas ideas?
Solución
El problema con mi enfoque fue que estaba enviando el Content-Type
encabezado incorrecto con todas mis solicitudes. Entonces, el único cambio necesario para que el código funcione correctamente es eliminar el Content-Type = application/json
encabezado HTTP. Entonces el código correcto sería este:
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];
Enviar imágenes junto con otros parámetros
Si necesita publicar imágenes junto con otros parámetros usando NSURLSession
aquí, tiene un ejemplo:
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];
fuente
NSURLSessionUploadTask
, publica datos sin procesar en su servidor. Con el que aún puede trabajar, por ejemplo, a través defile_get_contents('php://input') in PHP
, pero debe incluir otros datos en los encabezados.Content-Type
todo lo que necesitaba para resolver las cosas. ¡Gracias!Respuestas:
Podría intentar usar un NSDictionary para los params. Lo siguiente enviará los parámetros correctamente a un servidor JSON.
Espero que esto ayude (estoy tratando de resolver un problema de autenticidad CSRF con lo anterior, pero envía los parámetros en NSDictionary).
fuente
NSJSONSerialization
) y he agregado el código para publicar imágenes junto con otros parámetros. He actualizado la publicación original. Gracias por su ayuda :-)Motivación
A veces he recibido algunos errores cuando desea pasar httpBody serializado
Data
desdeDictionary
, lo que en la mayoría de los casos se debe a la codificación incorrecta o a los datos mal formados debido a objetos no conformes con NSCoding en elDictionary
.Solución
Dependiendo de sus requisitos, una solución fácil sería crear una en
String
lugar deDictionary
y convertirlaData
. Tiene los ejemplos de código a continuación escritos enObjective-C
ySwift 3.0
.C objetivo
Rápido
fuente
url
, a continuación,method
a continuación,body
lo que debe ser mutable? Y si ese es el caso, ¿dónde necesitaría usarNSURLRequest
?Puede usar https://github.com/mxcl/OMGHTTPURLRQ
fuente
La solución Swift 2.0 está aquí:
fuente
Si está utilizando Swift, la biblioteca Just lo hace por usted. Ejemplo de su archivo readme:
fuente
El código de Teja Kumar Bethina cambió para Swift 3:
fuente
fuente
-[NSUserDefaults synchronize]
. De la documentación de Apple "este método es innecesario y no debe usarse".