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. ส่งคำขอของคุณใน 2 วิธีโดยใช้NSURLConnection:

    • พร้อมกัน: (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error

      ส่งคืนNSDataตัวแปรที่คุณสามารถดำเนินการได้

      สำคัญ: อย่าลืมเริ่มต้นคำขอซิงโครนัสในเธรดแยกต่างหากเพื่อหลีกเลี่ยงการบล็อก UI

    • พร้อมกัน (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/… แม้ว่าคุณจะรู้ดีพอที่จะยุ่งเกี่ยวกับเธรดที่แตกต่างกัน แต่คุณก็อาจจะสบายดี
Aaron Brown

@Anh ดีคำตอบ didReceiveAuthenticationChallengeแต่ฉันเป็นเพียงเล็กน้อยสงสัยด้วยวิธีการที่ผ่านมา มีปัญหาด้านความปลอดภัยเกี่ยวกับรหัสผ่าน / ชื่อผู้ใช้ที่เข้ารหัสยากหรือไม่? มีวิธีแก้ไขไหม?
Sam Spencer

2
โดยทั่วไปแล้วคุณจะเก็บข้อมูลประจำตัวไว้ในพวงกุญแจและดึงข้อมูลเหล่านั้นไว้ที่นั่นเพื่อจัดการ Basic-Auth
Anh Do

2
iOS 5 เป็นต้นไปนอกจากนี้ยังสามารถใช้ + (void) sendAsynchronousRequest: (NSURLRequest ) คำขอคิว (NSOperationQueue *) คิว completionHandler: (void (^) (NSURLResponse , NSData * NSError *)) จัดการ
chunkyguy

13

แก้ไข: ASIHTTPRequest ถูกทิ้งร้างโดยนักพัฒนา มันยังคงเป็น IMO ที่ดีมาก แต่คุณควรดูที่อื่นตอนนี้

ฉันขอแนะนำให้ใช้ไลบรารี ASIHTTPRequestหากคุณกำลังจัดการ HTTPS แม้จะไม่มี https มันก็ให้เสื้อคลุมที่ดีสำหรับสิ่งนี้และในขณะที่มันไม่ยากที่จะทำด้วยตัวคุณเองผ่าน http ธรรมดา ๆ ฉันแค่คิดว่าห้องสมุดนั้นดีและเป็นวิธีที่ดีในการเริ่มต้น

ภาวะแทรกซ้อน HTTPS นั้นอยู่ไกลจากเรื่องเล็กน้อยในสถานการณ์ต่าง ๆ และถ้าคุณต้องการความแข็งแกร่งในการจัดการรูปแบบทั้งหมดคุณจะพบห้องสมุด ASI เป็นความช่วยเหลือที่แท้จริง


13
ไลบรารี ASIHTTPRequest ถูกยกเลิกอย่างเป็นทางการโดยผู้พัฒนาเนื่องจากสถานะการโพสต์นี้: allseeing-i.com/هrequest_release] ; ฉันขอแนะนำให้คุณใช้ห้องสมุดอื่น ๆ ตามที่นักพัฒนาแนะนำหรือดีกว่านั้นลองเรียนรู้ NSURLRequest :) ไชโย
Goles

@ Mr.Gando - ลิงค์ของคุณใช้งานไม่ได้โปรดทราบว่าเซมิโคลอนมีความสำคัญ ที่กล่าวว่าน่าเศร้ามากที่เห็นมันถูกทิ้งร้าง มันตรวจสอบสิ่งต่าง ๆ ได้ดีมาก ๆ และมันก็เป็นงานที่ต้องทำซ้ำทั้งหมด ... อัปยศ ...
Roger

และลิงก์นั้นก็ใช้งานไม่ได้ สำหรับใครก็ตามที่พยายามจะหามันโปรดทราบว่า url ที่ถูกต้องนั้นต้องมีเซมิโคลอนอยู่ท้าย ๆ - SO เป็นสาเหตุของ; ที่จะแยกออกจากลิงก์ที่ผู้คนโพสต์
Roger

3
AFNetworkingเป็นสิ่งที่คนส่วนใหญ่ใช้กันอยู่ในตอนนี้
Vadoff

7

ฉันคิดว่าฉันจะอัปเดตโพสต์นี้เล็กน้อยและบอกว่าชุมชน iOS จำนวนมากได้ย้ายไปที่AFNetworkingหลังจากนั้นASIHTTPRequestถูกทอดทิ้ง ฉันขอแนะนำอย่างยิ่ง มันเป็นเสื้อคลุมที่ดีรอบ ๆNSURLConnectionและช่วยให้การโทรแบบอะซิงโครนัสและสิ่งที่คุณอาจต้องการ


2
ฉันรู้ว่าคำตอบที่ยอมรับนั้นดีไม่ได้หมายถึงพฤติกรรมหรืออะไร แต่สิ่งนี้ควรมี upvotes มากกว่านี้แน่นอน บางทีถ้ามีตัวอย่างและบางส่วนของรหัสถูกเพิ่มเข้าไปตามคำถามที่แนะนำ
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+ ปกติฉันจะ subclass 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];
}

หากคุณใช้ serializer ตอบสนอง JSON responseObject จะเป็นวัตถุจากการตอบสนอง JSON (มักจะเป็น NSDictionary หรือ NSArray)


1

หมายเหตุ: ตัวอย่าง Pure Swift 3 (Xcode 8): โปรดลองใช้ตัวอย่างรหัสต่อไปนี้ มันเป็นตัวอย่างง่ายๆของการทำงานของdataTaskURLSession

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

ใช้ 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:

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

}

ใช้ 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()

ทำงานได้ดีสำหรับฉัน .. ลองรับประกันผล 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];

}

หวังว่านี้จะตอบสนองความต้องการของคุณดังต่อไปนี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.