iOS: bagaimana cara melakukan permintaan HTTP POST?

127

Saya mendekati pengembangan iOS dan saya ingin memiliki salah satu aplikasi pertama saya untuk melakukan permintaan HTTP POST.

Sejauh yang saya bisa mengerti, saya harus mengelola koneksi yang menangani permintaan melalui NSURLConnectionobjek, yang memaksa saya untuk memiliki objek delegasi, yang pada gilirannya akan menangani peristiwa data.

Bisakah seseorang tolong menjelaskan tugas dengan contoh praktis?

Saya harus menghubungi titik akhir https mengirim data otentikasi (nama pengguna dan kata sandi) dan mendapatkan kembali respons teks biasa.

Federico Zancan
sumber

Jawaban:

166

Anda dapat menggunakan NSURLConnection sebagai berikut:

  1. Setel Anda NSURLRequest: Gunakan requestWithURL:(NSURL *)theURLuntuk menginisialisasi permintaan.

    Jika Anda perlu menentukan permintaan POST dan / atau tajuk HTTP, gunakan NSMutableURLRequestdengan

    • (void)setHTTPMethod:(NSString *)method
    • (void)setHTTPBody:(NSData *)data
    • (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field
  2. Kirim permintaan Anda dalam 2 cara menggunakan NSURLConnection:

    • Serentak: (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error

      Ini mengembalikan NSDatavariabel yang bisa Anda proses.

      PENTING: Ingatlah untuk memulai permintaan sinkron di utas terpisah untuk menghindari pemblokiran UI.

    • Secara serempak: (void)start

Jangan lupa untuk mengatur delegasi NSURLConnection Anda untuk menangani koneksi sebagai berikut:

- (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];
}
Anh Do
sumber
4
Apple mengatakan bahwa menggunakan permintaan sinkron "tidak disarankan" developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/... meskipun jika Anda cukup tahu untuk dipusingkan dengan utas yang berbeda, Anda mungkin akan baik-baik saja.
Aaron Brown
@ Anh Jawaban Bagus, tapi saya agak skeptis dengan metode terakhir didReceiveAuthenticationChallenge. Apakah ada masalah keamanan dengan kata sandi / nama pengguna hard-coding? Apakah ada cara untuk mengatasi ini?
Sam Spencer
2
Secara umum Anda akan menyimpan kredensial di gantungan kunci dan mengambilnya di sana untuk menangani Basic-Auth.
Anh Do
2
iOS 5 dan seterusnya dapat juga menggunakan + (void) kirimAkronronRequest: (NSURLRequest ) antrian permintaan: (NSOperationQueue *) penyelesaian antrianHandler: (void (^) (NSURLResponse , NSData *, NSError *)) handler
chunkyguy
13

EDIT: ASIHTTPRequest telah ditinggalkan oleh pengembang. Ini masih IMO yang sangat bagus, tetapi Anda mungkin harus mencari di tempat lain sekarang.

Saya sangat merekomendasikan menggunakan perpustakaan ASIHTTPRequest jika Anda menangani HTTPS. Bahkan tanpa https itu menyediakan pembungkus yang sangat bagus untuk hal-hal seperti ini dan sementara itu tidak sulit untuk melakukannya sendiri melalui http polos, saya hanya berpikir perpustakaan itu bagus dan cara yang bagus untuk memulai.

Komplikasi HTTPS jauh dari sepele dalam berbagai skenario, dan jika Anda ingin menjadi kuat dalam menangani semua variasi, Anda akan menemukan perpustakaan ASI sangat membantu.

Roger
sumber
13
Pustaka ASIHTTPRequest telah ditinggalkan secara resmi oleh pengembangnya sebagaimana dinyatakan oleh pos ini: allseeing-i.com/[request_release] ; , Saya akan merekomendasikan Anda untuk menggunakan perpustakaan lain seperti yang disarankan pengembang, atau bahkan lebih baik, cobalah untuk belajar NSURLRequest :) Ceria.
Goles
@ Mr.Gando - tautan Anda tampaknya tidak berfungsi - perhatikan bahwa titik koma adalah signifikan. Yang mengatakan, SANGAT sedih melihatnya ditinggalkan. Itu banyak hal otentikasi benar-benar baik dan itu banyak pekerjaan untuk mereplikasi semuanya ... memalukan ...
Roger
Dan tautan itu juga tidak berfungsi. Bagi siapa pun yang mencoba menemukannya, harap perhatikan bahwa url yang benar memerlukan titik koma di ujungnya - SO menyebabkan; untuk dikecualikan dari tautan yang diposkan orang.
Roger
3
AFNetworking adalah apa yang tampaknya kebanyakan orang gunakan sekarang.
Vadoff
7

Saya pikir saya akan memperbarui posting ini sedikit dan mengatakan bahwa banyak komunitas iOS telah pindah ke AFNetworking setelah ASIHTTPRequestditinggalkan. Saya sangat merekomendasikannya. Ini adalah pembungkus hebat NSURLConnectiondan memungkinkan untuk panggilan tidak sinkron, dan pada dasarnya apa pun yang Anda butuhkan.

Jesse Naugher
sumber
2
Saya tahu jawaban yang diterima baik, tidak bermaksud untuk bersikap atau apa pun, tetapi ini pasti harus memiliki lebih banyak suara positif. Mungkin jika contoh dan beberapa fragmen kode ditambahkan, seperti yang disarankan pertanyaan?
acrespo
6

Ini jawaban yang diperbarui untuk iOS7 +. Ini menggunakan NSURLSession, kepanasan baru. Penafian, ini belum diuji dan ditulis dalam bidang teks:

- (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]);
}

Atau lebih baik lagi, gunakan AFNetworking 2.0+. Biasanya saya akan subclass AFHTTPSessionManager, tapi saya menempatkan ini semua dalam satu metode untuk memiliki contoh singkat.

- (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];
}

Jika Anda menggunakan serializer respons JSON, responseObject akan menjadi objek dari respons JSON (seringkali NSDictionary atau NSArray).

Kyle Robson
sumber
1

CATATAN: Pure Swift 3 (Xcode 8) contoh: Silakan coba kode sampel berikut. Ini adalah contoh sederhana dari dataTaskfungsi 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()

    }
Dinesh
sumber
0

Xcode 8 dan Swift 3.0

Menggunakan URLSession:

 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 Delegate call:

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){

}

Menggunakan Block 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()

Bekerja dengan baik untuk saya .. coba 100% jaminan hasil

Saumil Shah
sumber
0

Berikut adalah cara kerja permintaan HTTP POST untuk iOS 8+ menggunakan 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];

}

Semoga ini memenuhi kebutuhan Anda sebagai berikut.

Abilash Balasubramanian
sumber