iOS 网络编程:POST请求与GET请求

大多数app都会使用到网络请求,现在做得比较完善的三方请求有ASIHttpRequest、AFNetworking和MKNetworkKit三种。但是因为ASIHttpRequest已经很长时间没有更新了,所以选择的时候,还请慎重。

在初学网络请求的时候,我也自己封装了POST和GET请求。关于图片上传,我专门写了一篇文章,详细的介绍见:

http://www.saitjr.com/ios/ios-network-upload-image.html

另外,我也封装了一个网络请求框架,采用的是三层网络请求层次,详细的介绍见:

http://www.saitjr.com/ios/ios-network-foundation.html?

网络请求和网络请求框架下载地址:

https://github.com/saitjr/TJRNetworkConnection

环境信息:

Mac OS X 10.9.3

Xcode 5.1.1

IOS 7.1

正文:

一、需要用的知识点

1. GET/POST请求区别:

GET : get请求的参数拼接在url地址后面,而url地址的长度是有限制的,所以get请求请求的数据长度有限,一般用户数据量比较的请求(如:页面跳转操作等)。虽然登录操作的数据量也非常小,但是因为get参数的url地址栏中,登录密码等信息会直接暴露出来,所以,登录操作的密码即使加密,也会使用post请求来完成。

POST : post请求弥补了get请求的明文、数据量小等缺陷,在网络请求中非常常见。

2. 同步/异步请求区别:

同步 : 同步请求会直接在主线程中进行操作,关于线程与进程,这里有一个比较简单的解释。主线程一般做界面刷新等操作,然而同步请求将会导致界面卡死,有非常不好的用户体验,所以在选择上,一般使用异步请求。在我看来,用到同步请求的地方,一般是开始界面。如果在app的首页要有数据请求,那么可以使用同步请求,让界面卡死在开始界面,当数据请求完成以后,在进入到首页,防止数据还未请求完成就跳转到首页,给用户带来不好的体验。

异步 : 异步请求会单开一个线程,所以不会阻塞主线程,从而界面不会卡死。

3. block代码块

在我封装的这个网络请求中,回调方法会使用到block,对于block的基础知识和内存管理,我在《block的使用与内存管理》中有介绍。

二、代码实现四种网路请求(GET同步、GET异步、POST同步、POST异步)

1. GET同步请求


/**
 *  发起GET同步请求
 *
 *  @param method     网络请求地址
 *  @param parameters 参数
 *  @param callback   回调方法
 */
- (void)sendGetSynchronizeRequestWithMethod:(NSString *)method parameters:(NSDictionary *)parameters callback:(Callback)callback {
    
    // 发起请求
    NSError *error = nil;
    // 配置get请求参数(configGetUrlRequestWithMethod方法将在后面介绍) 、接收请求返回数据
    NSData *data = [NSURLConnection sendSynchronousRequest:[self configGetUrlRequestWithMethod:method parameters:parameters] returningResponse:nil error:&error];

    if (error) {
        // 如果出错,就输出错误,并回调
        NSLog(@"request did failed with error message '%@'", [error localizedDescription]);
        callback(error, nil);
    } else {
        // JSON解析,回调
        NSMutableDictionary *object = [selfJSONObjectWithData:data];
        callback(nil, object);
    }
}

2. GET异步请求

GET异步请求需要实现NSURLConnectionDataDelegate代理方法


- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data; // 接收到数据
- (void)connectionDidFinishLoading:(NSURLConnection *)connection; // 加载完成(数据全部接受完)
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error; // 网络请求

发起GET异步请求


/**
 *  发起GET异步请求
 *
 *  @param method     网络请求地址
 *  @param parameters 参数
 *  @param callback   回调方法
 */
- (void)sendGetAsynchronizeRequestWithMethod:(NSString *)method parameters:(NSDictionary *)parameters callback:(Callback)callback {
    
    self.callback = callback;
 // 配置get请求参数(configGetUrlRequestWithMethod方法将在后面介绍) 、接收请求返回数据
    [NSURLConnection connectionWithRequest:[self configPostURLRequestWithMethod:method parameters:parameters] delegate:self];
}

代理方法实现


/**
 *  接收到数据时的代理
 *
 *  @param connection 网络连接
 *  @param data       接收到的数据
 */
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    
    if (!_responseData) {
        
        _responseData = [[NSMutableData alloc] init];
    }
    
    // 在数据量较大时,会多次走这个方法,接收数据,需要将每次接收到的数据拼接起来
    [_responseData appendData:data];
 }

/**
 *  请求完成代理
 *
 *  @param connection 网络连接
 */
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    
    // 关闭网络连接
    [connection cancel];
    
    // JSON解析
    id object = [self JSONObjectWithData:_responseData];
    
    // 将接收数据的参数赋空,用于下次请求继续接收新的数据
    _responseData.length = 0;
    
    // 如果有回调方法,则走回调方法
    if (_callback) {
        
        _callback(nil, object);
    }
    // 释放回调方法
    self.callback = nil;
 }

/**
 *  请求出错代理
 *
 *  @param connection 网络连接
 *  @param error      错误
 */
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    
    // 关闭网络连接
    [connection cancel];
    
    // 如果有回调方法,则走回调方法
    if (_callback) {
        
        _callback(error, nil);
    }
    // 释放回调方法
    self.callback = nil;
}

3. GET请求参数配置 : 将GET请求的参数拼接在url之后


/**
 *  配置GET请求
 *
 *  @param method     网络请求地址
 *  @param parameters 参数
 *
 *  @return配置完成的请求
 */
- (NSURLRequest *)configGetUrlRequestWithMethod:(NSString *)method parameters:(NSDictionary *)parameters {
    
    // 因为GET的参数是拼接在URL地址后面的,所以将method参数copy为可变字符串
    NSMutableString *httpBodyString = [method mutableCopy];
    
    // GET请求的URL地址在参数前,需要加上?,表示参数列表开始
    [httpBodyString appendString:@"?"];
    
    // 循环将参数拼接到URL后面
    for (NSString *key in parameters) {

        [httpBodyString appendFormat:@"%@=%@&", key, [parameters objectForKey:key]];
    }
    
    // 将string转为URL
    NSURL *url = [NSURL URLWithString:httpBodyString];
    //通过url生成网络请求
    return [NSURLRequest requestWithURL:url];
}

4. 请求完成后,JSON数据解析


/**
 *  JSON解析返回数据
 *
 *  @param data 返回的数据
 *
 *  @return解析为JSON对象
 */
- (id)JSONObjectWithData:(NSData *)data {
    
    // 如果没有数据返回,则直接不解析
    if (data.length == 0) {
        
        return nil;
    }
    
    // 初始化解析错误
    NSError *error = nil;
    
    // JSON解析
    id object = [NSJSONSerializationJSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
    return object;
 }

5. POST同步请求


/**
 *  发起POST同步请求
 *
 *  @param method     网络请求地址
 *  @param parameters 参数
 *  @param callback   回调方法
 */
- (void)sendPostSynchronizeRequestWithMethod:(NSString *)method parameters:(NSDictionary *)parameters callback:(Callback)callback {
    
    // 发起请求
    NSError *error = nil;
    // post参数配置(configPostURLRequestWithMethod会在后面介绍) 接收请求返回的数据
    NSData *data = [NSURLConnection sendSynchronousRequest:[self configPostURLRequestWithMethod:method parameters:parameters] returningResponse:nil error:&error];
    
    if (error) {
        
        // 如果出错,就输出错误,并回调
        NSLog(@"request did failed with error message '%@'", [error localizedDescription]);
        callback(error, nil);
    } else {
        
        // JSON解析,回调
        NSMutableDictionary *object = [selfJSONObjectWithData:data];
        callback(nil, object);
    }
}

6. POST异步请求


/**
 *  发起POST异步请求
 *
 *  @param method     网络请求地址
 *  @param parameters 参数
 *  @param callback   回调方法
 */
- (void)sendPostAsynchronizeRequestWithMethod:(NSString *)method parameters:(NSDictionary *)parameters callback:(Callback)callback {
    
    self.callback = callback;
    
    [NSURLConnection connectionWithRequest:[self configPostURLRequestWithMethod:method parameters:parameters] delegate:self];
}

7. POST请求参数配置


/**
 *  配置POST请求
 *
 *  @param method     网络请求地址
 *  @param parameters 参数
 *
 *  @return配置完成的请求
 */
- (NSURLRequest *)configPostURLRequestWithMethod:(NSString *)method parameters:(NSDictionary *)parameters {
    
    // POST请求的参数是放在httpbody中的,所以可以先将请求地址转为url
    NSURL *url = [NSURLURLWithString:method];
    // 需要不停地拼接参数,所以request需要是可变的
    NSMutableURLRequest *request = [NSMutableURLRequestrequestWithURL:url];
    // 配置请求方法
    request.HTTPMethod = @"POST";
    // 请求超时时长
    request.timeoutInterval = 10;
    
    // 配置请求参数
    NSMutableString *httpBodyString = [NSMutableStringstring];
    for (NSString *key in parameters) {
        
        [httpBodyString appendFormat:@"%@=%@&", key, [parameters objectForKey:key]];
    }
    // 将参数加在httpbody中
    request.HTTPBody = [httpBodyString dataUsingEncoding:NSUTF8StringEncoding];
    
    return request;
}

8. POST异步请求代理方法

POST异步请求代理和GET异步请求代理方法相同,不再赘述

?总结:

在这四种请求方式中,参数配置GET用的一种,POST用的一种,因为他们的参数一个在URL上,一个在httpbody中。

而异步请求的代理,GET和POST是相同的。

封装完成以后,在使用到网络请求的地方,只需要选择使用哪一种网络请求就可以了,而不需要每一次都进行参数配置、数据解析等操作。

关于网络请求框架,则是在网络请求封装上再封装了一层,使结构更加请求,调用更加方便,有需要的请移步:

http://www.brighttj.com/ios/ios-network-foundation.html?

 

《iOS 网络编程:POST请求与GET请求》有3个想法

  1. 您好,因为最近要做登录,看到您的项目,就下载看了,但是发现 “RequestBase+LoginRequest.h”这个类没有了。可以发我一份吗?我邮箱18620212950@163.com 万分感谢!

  2. 你好 ,我最近做登录注册,下载看了你的项目,但是发现缺少RequestBase+LoginRequest.h这个类,可以发我吗?我邮箱m15213202723@163.com.谢谢啊

发表评论

电子邮件地址不会被公开。