iOS: як виконати HTTP POST-запит?


128

Я наближаюся до розробки iOS, і я хотів би мати одне із своїх перших додатків для виконання HTTP POST-запиту.

Наскільки я можу зрозуміти, я повинен керувати з'єднанням, яке обробляє запит через NSURLConnectionоб'єкт, що змушує мене мати об'єкт-делегат, який, в свою чергу, буде обробляти події даних.

Чи може хтось, будь ласка, уточнити завдання на практичному прикладі?

Мені слід зв’язатись із кінцевою точкою https, що надсилає дані автентифікації (ім’я користувача та пароль) та отримує відповідь із простим текстом.

Відповіді:


167

Ви можете використовувати NSURLConnection наступним чином:

  1. Встановіть NSURLRequest: Використовуйте requestWithURL:(NSURL *)theURLдля ініціалізації запиту.

    Якщо вам потрібно вказати запит POST і / або HTTP заголовки, використовувати NSMutableURLRequestз

    • (void)setHTTPMethod:(NSString *)method
    • (void)setHTTPBody:(NSData *)data
    • (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field
  2. Надішліть запит двома способами, використовуючи NSURLConnection:

    • Синхронно: (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error

      Це повертає NSDataзмінну, яку ви можете обробити.

      ВАЖЛИВО: Не забудьте запустити синхронний запит окремим потоком, щоб уникнути блокування інтерфейсу користувача.

    • Асинхронно: (void)start

Не забудьте встановити делегата NSURLConnection для обробки з'єднання наступним чином:

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
    [self.data setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)d {
    [self.data appendData:d];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    [[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error", @"")
                                 message:[error localizedDescription]
                                delegate:nil
                       cancelButtonTitle:NSLocalizedString(@"OK", @"") 
                       otherButtonTitles:nil] autorelease] show];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    NSString *responseText = [[NSString alloc] initWithData:self.data encoding:NSUTF8StringEncoding];

    // Do anything you want with it 

    [responseText release];
}

// Handle basic authentication challenge if needed
- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
    NSString *username = @"username";
    NSString *password = @"password";

    NSURLCredential *credential = [NSURLCredential credentialWithUser:username
                                                             password:password
                                                          persistence:NSURLCredentialPersistenceForSession];
    [[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
}

4
Apple каже, що використання синхронних запитів "не рекомендується" developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/…, хоча якщо ви знаєте достатньо, щоб повозитися з різними потоками, ви, ймовірно, будете добре.
Аарон Браун

@Anh Nice Answer, але я був трохи скептично поставлений до останнього методу didReceiveAuthenticationChallenge. Чи є проблеми із безпекою щодо жорсткого кодування паролів / імен користувачів? Чи є спосіб обходити це?
Сем Спенсер

2
Як правило, ви зберігаєте облікові дані у брелоку та отримуєте їх там, щоб обробляти Basic-Auth.
Anh Do

2
iOS 5 також може використовувати + (void) sendAsynchronousRequest: (NSURLRequest ) чергу запитів: (NSOperationQueue *) завершення чергиHandler: (void (^) (NSURLResponse , NSData *, NSError *)) обробник
chunkyguy

13

EDIT: Розробник відмовився від ASIHTTPRequest. Це все-таки хороший ІМО, але вам, мабуть, слід шукати в іншому місці зараз.

Настійно рекомендую використовувати бібліотеку ASIHTTPRequest, якщо ви обробляєте HTTPS. Навіть без https він забезпечує дійсно гарну обгортку для таких матеріалів, і хоча це не важко зробити самостійно через звичайний http, я просто думаю, що бібліотека є приємною і чудовим способом розпочати роботу.

Ускладнення HTTPS далеко не тривіальні в різних сценаріях, і якщо ви хочете бути надійними в обробці всіх варіантів, ви знайдете бібліотеку ASI справжню допомогу.


13
Бібліотеку ASIHTTPRequest офіційно покинув розробник, оскільки в цій публікації зазначено: allseeing-i.com/ evidencerequest_release] ; , Я б рекомендував вам використовувати інші бібліотеки, як пропонує розробник, а ще краще, спробуйте дізнатися NSURLRequest :) Привіт.
Голес

@ Mr.Gando - схоже, що ваше посилання не працює - зауважте, що крапка з двокрапкою є значною. Це сказало, ДУЖЕ сумно бачити це покинутим. Це робить дуже багато справжніх справ про автентифікацію, і це дуже багато роботи, щоб повторити все це ... сором ...
Роджер

І це посилання також не працює. Для всіх, хто намагається його знайти, зауважте, що правильний URL вимагає напівкрапки на кінці - SO викликає; щоб бути виключеними із посилань, які публікують люди.
Роджер

3
AFNetworking - це те, чим, здається, зараз користується більшість людей.
Вадофф

7

Я думав, що трохи оновлю цю публікацію і скажу, що багато спільноти iOS перейшли до AFNetworking після того, як ASIHTTPRequestбуло відмовлено. Я дуже рекомендую його. Це чудова обгортка, яка NSURLConnectionдозволяє виконувати асинхронні дзвінки, і в основному все, що вам може знадобитися.


2
Я знаю, що прийнята відповідь хороша, не маю на увазі поводження чи що-небудь, але це, безумовно, повинно мати більше результатів. Можливо, якщо додати приклад та якийсь фрагмент коду, як підказує питання?
acrespo

6

Ось оновлена ​​відповідь для iOS7 +. Він використовує NSURLSession, нову гарячість. Застереження, це не перевірено і було написано в текстовому полі:

- (void)post {
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://example.com/dontposthere"] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
    // Uncomment the following two lines if you're using JSON like I imagine many people are (the person who is asking specified plain text)
    // [request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    // [request addValue:@"application/json" forHTTPHeaderField:@"Accept"]; 
    [request setHTTPMethod:@"POST"];
    NSURLSessionDataTask *postDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    }];
    [postDataTask resume];
}

-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(    NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler {
    completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
}

Або ще краще, використовуйте AFNetworking 2.0+. Зазвичай я б підклас AFHTTPSessionManager, але я все це вкладаю в один метод, щоб мати стислий приклад.

- (void)post {
    AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"https://example.com"]];
    // Many people will probably want [AFJSONRequestSerializer serializer];
    manager.requestSerializer = [AFHTTPRequestSerializer serializer];
    // Many people will probably want [AFJSONResponseSerializer serializer];
    manager.responseSerializer = [AFHTTPRequestSerializer serializer];
    manager.securityPolicy.allowInvalidCertificates = NO; // Some servers require this to be YES, but default is NO.
    [manager.requestSerializer setAuthorizationHeaderFieldWithUsername:@"username" password:@"password"];
    [[manager POST:@"dontposthere" parameters:nil success:^(NSURLSessionDataTask *task, id responseObject) {
        NSString *responseString = [[NSString alloc] initWithData:responseObject encoding:NSUTF8StringEncoding];
    } failure:^(NSURLSessionDataTask *task, NSError *error) {
        NSLog(@"darn it");
    }] resume];
}

Якщо ви використовуєте серіалізатор відповідей JSON, responseObject буде об'єктом відповіді JSON (часто NSDictionary або NSArray).


1

ПРИМІТКА: Приклад Pure Swift 3 (Xcode 8): Будь ласка, спробуйте наступний зразок коду. Це простий приклад dataTaskфункції URLSession.

func simpleDataRequest() {

        //Get the url from url string
        let url:URL = URL(string: "YOUR URL STRING")!

        //Get the session instance
        let session = URLSession.shared

        //Create Mutable url request
        var request = URLRequest(url: url as URL)

        //Set the http method type
        request.httpMethod = "POST"

        //Set the cache policy
        request.cachePolicy = URLRequest.CachePolicy.reloadIgnoringCacheData

        //Post parameter
        let paramString = "key=value"

        //Set the post param as the request body
        request.httpBody = paramString.data(using: String.Encoding.utf8)

        let task = session.dataTask(with: request as URLRequest) {
            (data, response, error) in

            guard let _:Data = data as Data?, let _:URLResponse = response  , error == nil else {

                //Oops! Error occured.
                print("error")
                return
            }

            //Get the raw response string
            let dataString = String(data: data!, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue))

            //Print the response
            print(dataString!)

        }

        //resume the task
        task.resume()

    }

0

Xcode 8 і Swift 3.0

Використання URL-сесії:

 let url = URL(string:"Download URL")!
 let req = NSMutableURLRequest(url:url)
 let config = URLSessionConfiguration.default
 let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)

 let task : URLSessionDownloadTask = session.downloadTask(with: req as URLRequest)
task.resume()

Виклик делегата URLSession:

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {

}


func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, 
didWriteData bytesWritten: Int64, totalBytesWritten writ: Int64, totalBytesExpectedToWrite exp: Int64) {
                   print("downloaded \(100*writ/exp)" as AnyObject)

}

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL){

}

Використання блоку GET / POST / PUT / DELETE:

 let request = NSMutableURLRequest(url: URL(string: "Your API URL here" ,param: param))!,
        cachePolicy: .useProtocolCachePolicy,
        timeoutInterval:"Your request timeout time in Seconds")
    request.httpMethod = "GET"
    request.allHTTPHeaderFields = headers as? [String : String] 

    let session = URLSession.shared

    let dataTask = session.dataTask(with: request as URLRequest) {data,response,error in
        let httpResponse = response as? HTTPURLResponse

        if (error != nil) {
         print(error)
         } else {
         print(httpResponse)
         }

        DispatchQueue.main.async {
           //Update your UI here
        }

    }
    dataTask.resume()

Для мене добре працює .. спробуйте 100% гарантію результату


0

Ось як POST HTTP-запит працює для iOS 8+ за допомогою NSURLSession:

- (void)call_PostNetworkingAPI:(NSURL *)url withCompletionBlock:(void(^)(id object,NSError *error,NSURLResponse *response))completion
{
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    config.requestCachePolicy = NSURLRequestReloadIgnoringLocalCacheData;
    config.URLCache = nil;
    config.timeoutIntervalForRequest = 5.0f;
    config.timeoutIntervalForResource =10.0f;
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:nil];
    NSMutableURLRequest *Req=[NSMutableURLRequest requestWithURL:url];
    [Req setHTTPMethod:@"POST"];

    NSURLSessionDataTask *task = [session dataTaskWithRequest:Req completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        if (error == nil) {

            NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];
            if (dict != nil) {
                completion(dict,error,response);
            }
        }else
        {
            completion(nil,error,response);
        }
    }];
    [task resume];

}

Сподіваюся, це задовольнить вашу наступну вимогу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.