Отправить запрос POST с помощью NSURLSession
обновление: решение найдено. Вы можете прочитать его в конце поста.
Я пытаюсь выполнить запрос POST к удаленному REST API с помощью NSURLSession
. Идея в том, чтобы сделать запрос с двумя параметрами: deviceId
и textContent
.
проблема в том, что эти параметры не распознаются сервером. Серверная часть работает правильно, потому что я отправил сообщение с помощью POSTMAN для Google Chrome, и он работал отлично.
это код, который я использую прямо сейчас:
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];
Я пробовал ту же процедуру с 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];
какие идеи?
решение
проблема с моим подходом заключалась в том, что я отправлял неверный Content-Type
заголовок со всеми моими запросами. Поэтому единственное изменение, необходимое для правильной работы кода, - это удалить Content-Type = application/json
заголовок HTTP. Так что правильный код будет такой:
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];
отправка изображений вместе с другими параметры
Если вам нужно разместить изображения вместе с другими параметрами с помощью NSURLSession
вот вам пример:
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:@"--%@rn", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name="%@"rnrn", @"deviceId"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@rn", deviceID] dataUsingEncoding:NSUTF8StringEncoding]];
// Body part for "textContent" parameter. This is a string.
[body appendData:[[NSString stringWithFormat:@"--%@rn", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name="%@"rnrn", @"textContent"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"%@rn", 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:@"--%@rn", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name="%@"; filename="image.jpg"rn", @"image"] dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:[@"Content-Type: image/jpegrnrn" dataUsingEncoding:NSUTF8StringEncoding]];
[body appendData:imageData];
[body appendData:[[NSString stringWithFormat:@"rn"] dataUsingEncoding:NSUTF8StringEncoding]];
}
[body appendData:[[NSString stringWithFormat:@"--%@--rn", 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];
7 ответов:
вы можете попробовать использовать NSDictionary для параметров. Следующие параметры будут правильно отправлены на сервер JSON.
NSError *error; NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil]; NSURL *url = [NSURL URLWithString:@"[JSON SERVER"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0]; [request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; [request addValue:@"application/json" forHTTPHeaderField:@"Accept"]; [request setHTTPMethod:@"POST"]; NSDictionary *mapData = [[NSDictionary alloc] initWithObjectsAndKeys: @"TEST IOS", @"name", @"IOS TYPE", @"typemap", nil]; NSData *postData = [NSJSONSerialization dataWithJSONObject:mapData options:0 error:&error]; [request setHTTPBody:postData]; NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { }]; [postDataTask resume];
надеюсь, что это поможет (я пытаюсь отсортировать проблему подлинности CSRF с выше - но он отправляет параметры в NSDictionary).
мотивация
иногда я получаю некоторые ошибки, когда вы хотите передать httpBody сериализован в
Data
СDictionary
, что в большинстве случаев происходит из-за неправильного кодирования или искаженных данных из-за не NSCoding соответствующие объекты вDictionary
.решение
в зависимости от ваших требований одним простым решением было бы создать
String
вместоDictionary
и преобразовать его вData
. У вас есть примеры кода ниже написаны наObjective-C
иSwift 3.0
.С
// Create the URLSession on the default configuration NSURLSessionConfiguration *defaultSessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultSessionConfiguration]; // Setup the request with URL NSURL *url = [NSURL URLWithString:@"yourURL"]; NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url]; // Convert POST string parameters to data using UTF8 Encoding NSString *postParams = @"api_key=APIKEY&email=example@example.com&password=password"; NSData *postData = [postParams dataUsingEncoding:NSUTF8StringEncoding]; // Convert POST string parameters to data using UTF8 Encoding [urlRequest setHTTPMethod:@"POST"]; [urlRequest setHTTPBody:postData]; // Create dataTask NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithRequest:urlRequest completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { // Handle your response here }]; // Fire the request [dataTask resume];
Свифт
// Create the URLSession on the default configuration let defaultSessionConfiguration = URLSessionConfiguration.default let defaultSession = URLSession(configuration: defaultSessionConfiguration) // Setup the request with URL let url = URL(string: "yourURL") var urlRequest = URLRequest(url: url!) // Note: This is a demo, that's why I use implicitly unwrapped optional // Convert POST string parameters to data using UTF8 Encoding let postParams = "api_key=APIKEY&email=example@example.com&password=password" let postData = postParams.data(using: .utf8) // Set the httpMethod and assign httpBody urlRequest.httpMethod = "POST" urlRequest.httpBody = postData // Create dataTask let dataTask = defaultSession.dataTask(with: urlRequest) { (data, response, error) in // Handle your response here } // Fire the request dataTask.resume()
вы можете использовать https://github.com/mxcl/OMGHTTPURLRQ
id config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:someID]; id session = [NSURLSession sessionWithConfiguration:config delegate:someObject delegateQueue:[NSOperationQueue new]]; OMGMultipartFormData *multipartFormData = [OMGMultipartFormData new]; [multipartFormData addFile:data1 parameterName:@"file1" filename:@"myimage1.png" contentType:@"image/png"]; NSURLRequest *rq = [OMGHTTPURLRQ POST:url:multipartFormData]; id path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"upload.NSData"]; [rq.HTTPBody writeToFile:path atomically:YES]; [[session uploadTaskWithRequest:rq fromFile:[NSURL fileURLWithPath:path]] resume];
Если вы используете Swift, то просто библиотека сделает это за вас. Пример из файла readme:
// talk to registration end point Just.post( "http://justiceleauge.org/member/register", data: ["username": "barryallen", "password":"ReverseF1ashSucks"], files: ["profile_photo": .URL(fileURLWithPath:"flash.jpeg", nil)] ) { (r) if (r.ok) { /* success! */ } }
Swift 2.0 решение здесь:
let urlStr = “http://url_to_manage_post_requests” let url = NSURL(string: urlStr) let request: NSMutableURLRequest = NSMutableURLRequest(URL: url!) request.HTTPMethod = "POST" request.setValue(“application/json” forHTTPHeaderField:”Content-Type”) request.timeoutInterval = 60.0 //additional headers request.setValue(“deviceIDValue”, forHTTPHeaderField:”DeviceId”) let bodyStr = “string or data to add to body of request” let bodyData = bodyStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true) request.HTTPBody = bodyData let session = NSURLSession.sharedSession() let task = session.dataTaskWithRequest(request){ (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in if let httpResponse = response as? NSHTTPURLResponse { print("responseCode \(httpResponse.statusCode)") } if error != nil { // You can handle error response here print("\(error)") }else { //Converting response to collection formate (array or dictionary) do{ let jsonResult: AnyObject = (try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)) //success code }catch{ //failure code } } } task.resume()
код Teja Kumar Bethina изменился на Swift 3:
let urlStr = "http://url_to_manage_post_requests" let url = URL(string: urlStr) var request: URLRequest = URLRequest(url: url!) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField:"Content-Type") request.timeoutInterval = 60.0 //additional headers request.setValue("deviceIDValue", forHTTPHeaderField:"DeviceId") let bodyStr = "string or data to add to body of request" let bodyData = bodyStr.data(using: String.Encoding.utf8, allowLossyConversion: true) request.httpBody = bodyData let task = URLSession.shared.dataTask(with: request) { (data: Data?, response: URLResponse?, error: Error?) -> Void in if let httpResponse = response as? HTTPURLResponse { print("responseCode \(httpResponse.statusCode)") } if error != nil { // You can handle error response here print("\(error)") } else { //Converting response to collection formate (array or dictionary) do { let jsonResult = (try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers)) //success code } catch { //failure code } } } task.resume()
use like this..... Create file #import <Foundation/Foundation.h>` #import "SharedManager.h" #import "Constant.h" #import "UserDetails.h" @interface APISession : NSURLSession<NSURLSessionDelegate> @property (nonatomic, retain) NSMutableData *responseData; +(void)postRequetsWithParam:(NSMutableDictionary* )objDic withAPIName:(NSString* )strAPIURL completionHandler:(void (^)(id result, BOOL status))completionHandler; @end ****************.m************************* #import "APISession.h" #import <UIKit/UIKit.h> @implementation APISession +(void)postRequetsWithParam:(NSMutableDictionary *)objDic withAPIName:(NSString *)strAPIURL completionHandler:(void (^)(id, BOOL))completionHandler { NSURL *url=[NSURL URLWithString:strAPIURL]; NSMutableURLRequest *request=[[NSMutableURLRequest alloc]initWithURL:url]; [request setHTTPMethod:@"POST"]; [request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; NSError *err = nil; NSData *data=[NSJSONSerialization dataWithJSONObject:objDic options:NSJSONWritingPrettyPrinted error:&err]; [request setHTTPBody:data]; NSString *strJsonFormat = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"API URL: %@ \t Api Request Parameter ::::::::::::::%@",url,strJsonFormat); // NSLog(@"Request data===%@",objDic); NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession *session = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]]; // NSURLSession *session=[NSURLSession sharedSession]; NSURLSessionTask *task=[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (error==nil) { NSDictionary *dicData=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:&error];\ NSLog(@"Response Data=============%@",dicData); if([[dicData valueForKey:@"tokenExpired"]integerValue] == 1) { NSLog(@"hello"); NSDictionary *dict = [NSDictionary dictionaryWithObject:@"Access Token Expire." forKey:@"message"]; [[NSNotificationCenter defaultCenter] postNotificationName:@"UserLogOut" object:self userInfo:dict]; } dispatch_async(dispatch_get_main_queue(), ^{ completionHandler(dicData,(error == nil)); }); NSLog(@"%@",dicData); } else{ dispatch_async(dispatch_get_main_queue(), ^{ completionHandler(error.localizedDescription,NO); }); } }]; // dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [task resume]; // }); } @end *****************************in .your view controller*********** #import "file" txtEmail.text = [txtEmail.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; { [SVProgressHUD showWithStatus:@"Loading..."]; [SVProgressHUD setDefaultMaskType:SVProgressHUDMaskTypeGradient]; NSMutableDictionary *objLoginDic=[[NSMutableDictionary alloc] init]; [objLoginDic setValue:txtEmail.text forKey:@"email"]; [objLoginDic setValue:@0 forKey:kDeviceType]; [objLoginDic setValue:txtPassword.text forKey:kPassword]; [objLoginDic setValue:@"376545432" forKey:kDeviceTokan]; [objLoginDic setValue:@"" forKey:kcountryId]; [objLoginDic setValue:@"" forKey:kfbAccessToken]; [objLoginDic setValue:@0 forKey:kloginType]; [APISession postRequetsWithParam:objLoginDic withAPIName:KLOGIN_URL completionHandler:^(id result, BOOL status) { [SVProgressHUD dismiss]; NSInteger statusResponse=[[result valueForKey:kStatus] integerValue]; NSString *strMessage=[result valueForKey:KMessage]; if (status) { if (statusResponse == 1) { UserDetails *objLoginUserDetail=[[UserDetails alloc] initWithObject:[result valueForKey:@"userDetails"]]; [[NSUserDefaults standardUserDefaults] setObject:@(objLoginUserDetail.userId) forKey:@"user_id"]; [[NSUserDefaults standardUserDefaults] synchronize]; [self clearTextfeilds]; HomeScreen *obj=[Kiran_Storyboard instantiateViewControllerWithIdentifier:@"HomeScreen"]; [self.navigationController pushViewController:obj animated:YES]; } else{ [strMessage showAsAlert:self]; } } }]; } **********use model class for represnt data************* #import <Foundation/Foundation.h> #import "Constant.h" #import <objc/runtime.h> @interface UserDetails : NSObject @property(strong,nonatomic) NSString *emailId, *deviceToken, *countryId, *fbAccessToken, *accessToken, *countryName, *isProfileSetup, *profilePic, *firstName, *lastName, *password; @property (assign) NSInteger userId,deviceType,loginType; -(id)initWithObject :(NSDictionary *)dicUserData; -(void)saveLoginUserDetail; +(UserDetails *)getLoginUserDetail; -(UserDetails *)getEmptyModel; - (NSArray *)allPropertyNames; -(void)printDescription; -(NSMutableDictionary *)getDictionary; @end ******************model.m************* #import "UserDetails.h" #import "SharedManager.h" @implementation UserDetails -(id)initWithObject :(NSDictionary *)dicUserData { self = [[UserDetails alloc] init]; if (self) { @try { [self setFirstName:([dicUserData valueForKey:@"firstName"] != [NSNull null])? [dicUserData valueForKey:@"firstName"]:@""]; [self setUserId:([dicUserData valueForKey:kUserId] != [NSNull null])? [[dicUserData valueForKey:kUserId] integerValue]:0]; } @catch (NSException *exception) { NSLog(@"Exception: %@",exception.description); } @finally { } } return self; } -(UserDetails *)getEmptyModel{ [self setFirstName:@""]; [self setLastName:@""]; [self setDeviceType:0]; return self; } - (void)encodeWithCoder:(NSCoder *)encoder { // Encode properties, other class variables, etc [encoder encodeObject:_firstName forKey:kFirstName]; [encoder encodeObject:[NSNumber numberWithInteger:_deviceType] forKey:kDeviceType]; } - (id)initWithCoder:(NSCoder *)decoder { if((self = [super init])) { _firstName = [decoder decodeObjectForKey:kEmailId]; _deviceType= [[decoder decodeObjectForKey:kDeviceType] integerValue]; } return self; } - (NSArray *)allPropertyNames { unsigned count; objc_property_t *properties = class_copyPropertyList([self class], &count); NSMutableArray *rv = [NSMutableArray array]; unsigned i; for (i = 0; i < count; i++) { objc_property_t property = properties[i]; NSString *name = [NSString stringWithUTF8String:property_getName(property)]; [rv addObject:name]; } free(properties); return rv; } -(void)printDescription{ NSMutableDictionary *dic = [[NSMutableDictionary alloc] init]; for(NSString *key in [self allPropertyNames]) { [dic setValue:[self valueForKey:key] forKey:key]; } NSLog(@"\n========================= User Detail ==============================\n"); NSLog(@"%@",[dic description]); NSLog(@"\n=============================================================\n"); } -(NSMutableDictionary *)getDictionary{ NSMutableDictionary *dic = [[NSMutableDictionary alloc] init]; for(NSString *key in [self allPropertyNames]) { [dic setValue:[self valueForKey:key] forKey:key]; } return dic; } #pragma mark #pragma mark - Save and get User details -(void)saveLoginUserDetail{ NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:self]; [Shared_UserDefault setObject:encodedObject forKey:kUserDefault_SavedUserDetail]; [Shared_UserDefault synchronize]; } +(UserDetails *)getLoginUserDetail{ NSData *encodedObject = [Shared_UserDefault objectForKey:kUserDefault_SavedUserDetail]; UserDetails *object = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject]; return object; } @end ************************usefull code while add data into model and get data******** NSLog(@"Response %@",result); NSString *strMessg = [result objectForKey:kMessage]; NSString *status = [NSString stringWithFormat:@"%@",[result objectForKey:kStatus]]; if([status isEqualToString:@"1"]) { arryBankList =[[NSMutableArray alloc]init]; NSMutableArray *arrEvents=[result valueForKey:kbankList]; ShareOBJ.isDefaultBank = [result valueForKey:kisDefaultBank]; if ([arrEvents count]>0) { for (NSMutableArray *dic in arrEvents) { BankList *objBankListDetail =[[BankList alloc]initWithObject:[dic mutableCopy]]; [arryBankList addObject:objBankListDetail]; } //display data using model... BankList *objBankListing =[arryBankList objectAtIndex:indexPath.row];