Atualização: Solução encontrada. Você pode lê-lo no final da postagem.
Estou tentando executar uma solicitação POST para uma API REST remota usando NSURLSession
. A idéia é fazer uma solicitação com dois parâmetros: deviceId
e textContent
.
O problema é que esses parâmetros não são reconhecidos pelo servidor. A parte do servidor funciona corretamente porque enviei um POST usando o POSTMAN para Google Chrome e funcionou perfeitamente.
Este é o código que estou usando agora:
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];
Eu tentei o mesmo procedimento com um 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];
Alguma ideia?
Solução
O problema com minha abordagem foi que eu estava enviando o Content-Type
cabeçalho incorreto com todas as minhas solicitações. Portanto, a única alteração necessária para o código funcionar corretamente é remover o Content-Type = application/json
cabeçalho HTTP. Portanto, o código correto seria 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];
Enviando imagens junto com outros parâmetros
Se você precisar postar imagens junto com outros parâmetros usando NSURLSession
aqui, você tem um exemplo:
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];
fonte
NSURLSessionUploadTask
, ele publica dados brutos no seu servidor. Com as quais você ainda pode trabalhar - por exemplo, viafile_get_contents('php://input') in PHP
-, mas é necessário incluir outros dados nos cabeçalhos.Content-Type
era tudo o que eu precisava para descobrir as coisas. Obrigado!Respostas:
Você pode tentar usar um NSDictionary para os parâmetros. A seguir, os parâmetros serão enviados corretamente para um servidor JSON.
Espero que isso ajude (estou tentando classificar um problema de autenticidade do CSRF com o acima exposto - mas ele envia os parâmetros no NSDictionary).
fonte
NSJSONSerialization
) e adicionei o código para postar imagens junto com outros parâmetros. Eu atualizei a postagem original. Obrigado por sua ajuda :-)Motivação
Às vezes, recebo alguns erros quando você deseja passar o httpBody serializado para
Data
fromDictionary
, o que na maioria dos casos se deve à codificação incorreta ou a dados malformados devido a objetos não compatíveis com NSCoding noDictionary
.Solução
Dependendo dos seus requisitos, uma solução fácil seria criar um em
String
vez deDictionary
e convertê-lo emData
. Você tem os exemplos de código abaixo escritos emObjective-C
eSwift 3.0
.Objetivo-C
Rápido
fonte
url
, em seguida,method
em seguida,body
por isso deve ser mutável? E se for esse o caso, onde seria necessário usarNSURLRequest
?Você pode usar https://github.com/mxcl/OMGHTTPURLRQ
fonte
A solução Swift 2.0 está aqui:
fonte
Se você estiver usando o Swift, a biblioteca Just fará isso por você. Exemplo do seu arquivo leia-me:
fonte
O código de Teja Kumar Bethina foi alterado para Swift 3:
fonte
fonte
-[NSUserDefaults synchronize]
. Na documentação da Apple "este método é desnecessário e não deve ser usado".