网络编程(二)

222 阅读8分钟

一. NSURLConnection常用方法(已弃用)

1.0 简介

NSURLConnection 是 2003 年 iOS 2.0 随着第一版 Safari 的发布而发布的,它不单单是一个网络请求类,而是指代 Foundation 框架的 URL 系统中的一系列关联的组件: NSURLRequest、NSURLResponse、NSURLProtocol、NSHTTPCookieStorage、NSURLCredentialStorage 以及同名类 NSURLConnection。

1.1 常用类

  • NSURL:请求地址
  • NSURLRequest:一个NSURLRequest对象就代表一个请求,, NSMutableURLReques是它的子类, 它包含的信息有
    • 一个NSURL对象
    • 请求方法、请求头、请求体
    • 请求超时… …
  • NSURLConnection
    • 负责发送请求,建立客户端和服务器的连接
    • 发送数据给服务器,并收集来自服务器的响应数据

1.2 使用步骤

  • 创建一个NSURL对象,设置请求路径

  • 传入NSURL创建一个NSURLRequest对象,设置请求头和请求体

  • 使用NSURLConnection发送请求

1904340-ad955fc405d4fe1c.png

1.3 NSURLRequest

设置请求超时等待时间(超过这个时间就算超时,请求失败)
- (void)setTimeoutInterval:(NSTimeInterval)seconds;

设置请求方法(比如GET和POST)
- (void)setHTTPMethod:(NSString *)method;

设置请求体
- (void)setHTTPBody:(NSData *)data;

设置请求头
- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field;

1.3 发送请求

  • 同步请求
  + (nullable NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse * _Nullable * _Nullable)response error:(NSError **)error;
  • 异步请求:根据对服务器返回数据的处理方式的不同,又可以分为2种
// block回调
+ (void)sendAsynchronousRequest:(NSURLRequest*) request                          queue:(NSOperationQueue*) queue                                                  completionHandler:(void (^)(NSURLResponse* response, NSData* data, NSError* connectionError)) handler;
// 代理
- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate;
+ (NSURLConnection*)connectionWithRequest:(NSURLRequest *)request delegate:(id)delegate;
- (id)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately;

在startImmediately = NO的情况下,需要调用start方法开始发送请求
- (void)start;
成为NSURLConnection的代理,要好遵守NSURLConnectionDataDelegate协议
<NSURLConnectionDataDelegate>协议中的代理方法
开始接收到服务器的响应时调用
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;

接收到服务器返回的数据时调用(服务器返回的数据比较大时会调用多次)
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;

服务器返回的数据完全接收完毕后调用
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;

请求出错时调用(比如请求超时)
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;

二. NSURLConnection网络请求

1.4 示例: get请求

- (void)getNetwork
{
    // 1.0 url
   NSURL *url = [NSURL URLWithString:@"https://apitest3.drstrong.cn/health-cure/cure/consult/count/not-handle?doctorId=35573&token=e8dc2e74694df8689089&ucDoctorId=625371"];
    
    // 2.0 创建请求体
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
    
    
    // 2.1 设置header
    [request setValue:@"13979af4eda34f70a305c70a0cb86c7b" forHTTPHeaderField:@"token"];
    
    // 3.0 同步请求
    NSHTTPURLResponse *response = nil;
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
    NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
    NSLog(@"%zd",response.statusCode);
    
    // 3.0 异步请求
    [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        //4.解析数据
        NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
        
        NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
        NSLog(@"%zd",res.statusCode);
        NSLog(@"%@",[NSThread currentThread]);
    }];
}

1.5 示例: post表单请求

- (void)postFromNetWork
{
    // 1.0 确定请求路径
    NSURL *url = [NSURL URLWithString:@"https://apitest3.drstrong.cn/health-doctor/checkVersion"];
    
    // 2.0 创建可变请求对象
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
    
    // 2.1 修改请求方法,POST必须大写
    [request setHTTPMethod:@"POST"];
    
    // 2.2 设置属性, 请求超时
    request.timeoutInterval = 5;
    
    // 2.3 设置header
    [request setValue:@"13979af4eda34f70a305c70a0cb86c7b" forHTTPHeaderField:@"token"];
    // 设置请求的格式from类型, 默认可以不设置
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    
    // 2.4 设置请求体
    request.HTTPBody = [@"doctorId=35573&paltform=iphone&token=e8dc2e74694df8689089&version=2.3.1" dataUsingEncoding:NSUTF8StringEncoding];
    
    
    // 3.0 异步请求
    [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        //4.解析数据
        NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
        
        NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
        NSLog(@"%zd",res.statusCode);
        NSLog(@"%@",[NSThread currentThread]);
    }];
}

1.6 示例: postJson请求

- (void)postJsonNetWork
{
    // 1.0 确定请求路径
    NSURL *url = [NSURL URLWithString:@"https://apitest3.drstrong.cn/health-im/im/group/infosNew?token=e8dc2e74694df8689089&doctorId=35573"];
    
    // 2.0 创建可变请求对象
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
    
    // 2.1 修改请求方法,POST必须大写
    [request setHTTPMethod:@"POST"];
    
    // 2.2 设置属性, 请求超时
    request.timeoutInterval = 5;
    
    // 2.3 设置header
    [request setValue:@"13979af4eda34f70a305c70a0cb86c7b" forHTTPHeaderField:@"token"];
    // 设置请求的格式json类型, 必须要设置
    [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    
    // 2.4 设置请求体
    NSMutableDictionary *bodyDic = [NSMutableDictionary dictionary];
    bodyDic[@"identityType"] = @"1";
    bodyDic[@"empty"] = @(NO);
    bodyDic[@"doctorId"] = @"35573";
    bodyDic[@"token"] = @"e8dc2e74694df8689089";
    bodyDic[@"groupIds"] = @"171565222264834,170922752409603";
    
    
   NSData *jsonData = [NSJSONSerialization dataWithJSONObject:bodyDic options:kNilOptions error:nil];
    request.HTTPBody = jsonData;
    
    // 3.0 异步请求
    [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        //4.解析数据
        NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
        
        NSHTTPURLResponse *res = (NSHTTPURLResponse *)response;
        NSLog(@"%zd",res.statusCode);
        NSLog(@"%@",[NSThread currentThread]);
    }];
}

1.7 示例: 代理请求


- (void)useSessionDelegate
{
    // 1.0 确定请求路径
    NSURL *url = [NSURL URLWithString:@"https://apitest3.drstrong.cn/health-doctor/checkVersion"];
    
    // 2.0 创建可变请求对象
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
    
    // 2.1 修改请求方法,POST必须大写
    [request setHTTPMethod:@"POST"];
    
    // 2.2 设置属性, 请求超时
    request.timeoutInterval = 5;
    
    // 2.3 设置header
    [request setValue:@"7b203782da1f4c50ba7e52cec9901b8a" forHTTPHeaderField:@"token"];
    // 设置请求的格式from类型, 默认可以不设置
    [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    
    // 2.4 设置请求体
    request.HTTPBody = [@"doctorId=35573&paltform=iphone&token=e8dc2e74694df8689089&version=2.3.1" dataUsingEncoding:NSUTF8StringEncoding];
    
    // 3.0 异步请求
    NSURLConnection *connect = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
    
    // 4.0  执行
    [connect start];
}

#pragma mark NSURLConnectionDataDelegate
//1.当接收到服务器响应的时候调用
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    NSLog(@"%s",__func__);
}

//2.接收到服务器返回数据的时候调用,调用多次
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    NSLog(@"%s",__func__);
    //拼接数据
    NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}
//3.当请求失败的时候调用
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
     NSLog(@"%s",__func__);
}

//4.请求结束的时候调用
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
     NSLog(@"%s",__func__);
}

三. 文件下载

1.0 示例: 下载(利用NSFileHandle句柄文件创建)

-(void)download3
{
   NSURL *url = [NSURL URLWithString:@"http://www.33lc.com/article/UploadPic/2012-10/2012102514201759594.jpg"];
    
    //2.创建请求对象
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    
    //设置请求头信息,告诉服务器值请求一部分数据range
    /*
     bytes=0-100 表示: 下载0到100个字节
     bytes=-100   表示: 下载最后100个字节
     bytes=50- 表示: 下载50个字节以后的所有数据
     */
    NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize];
    [request setValue:range forHTTPHeaderField:@"Range"];
    NSLog(@"+++++++%@",range);
    
    //3.发送请求
    NSURLConnection *connect = [[NSURLConnection alloc]initWithRequest:request delegate:self];
    self.connect = connect;
}

#pragma mark NSURLConnectionDataDelegate
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    NSLog(@"didReceiveResponse");
    
    //1.得到文件的总大小(本次请求的文件数据的总大小 != 文件的总大小)
    // self.totalSize = response.expectedContentLength + self.currentSize;
    
    if (self.currentSize >0) {
        return;
    }
    
    self.totalSize = response.expectedContentLength;
    
    //2.写数据到沙盒中
    self.fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]stringByAppendingPathComponent:@"123.jpg"];
    
    NSLog(@"%@",self.fullPath);
    
    //3.创建一个空的文件
    [[NSFileManager defaultManager] createFileAtPath:self.fullPath contents:nil attributes:nil];
    
    //NSDictionary *dict = [[NSFileManager defaultManager]attributesOfItemAtPath:self.fullPath error:nil];
    
    //4.创建文件句柄(指针)
    self.handle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath];
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    //1.移动文件句柄到数据的末尾
    [self.handle seekToEndOfFile];
    
    //2.写数据
    [self.handle writeData:data];
    
    //3.获得进度
    self.currentSize += data.length;
    
    //进度=已经下载/文件的总大小
    NSLog(@"%f",1.0 *  self.currentSize/self.totalSize);
    self.progressView.progress = 1.0 *  self.currentSize/self.totalSize;
    //NSLog(@"%@",self.fullPath);
}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    //1.关闭文件句柄
    [self.handle closeFile];
    self.handle = nil;
    
    NSLog(@"connectionDidFinishLoading");
    NSLog(@"%@",self.fullPath);
}   

1.1 示例: 下载(利用NSOutputStream输出流创建)

#pragma mark NSURLConnectionDataDelegate
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    NSLog(@"didReceiveResponse");
    
    //1.得到文件的总大小(本次请求的文件数据的总大小 != 文件的总大小)
    // self.totalSize = response.expectedContentLength + self.currentSize;
    
    if (self.currentSize >0) {
        return;
    }
    
    self.totalSize = response.expectedContentLength;
    
    //2.写数据到沙盒中
    self.fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]stringByAppendingPathComponent:@"123.jpg"];
    
    NSLog(@"%@",self.fullPath);
    //3.创建输出流
//    NSOutputStream
//    NSInputStream
    /*
     第一个参数:文件的路径
     第二个参数:YES 追加
     特点:如果该输出流指向的地址没有文件,那么会自动创建一个空的文件
     */
    NSOutputStream *stream = [[NSOutputStream alloc]initToFileAtPath:self.fullPath append:YES];
    
    //打开输出流
    [stream open];
    self.stream = stream;
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    //写数据
    [self.stream write:data.bytes maxLength:data.length];
    
    //3.获得进度
    self.currentSize += data.length;
    
    //进度=已经下载/文件的总大小
    NSLog(@"%f",1.0 *  self.currentSize/self.totalSize);
    self.progressView.progress = 1.0 *  self.currentSize/self.totalSize;
    //NSLog(@"%@",self.fullPath);
}

-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    
    //关闭流
    [self.stream close];
    self.stream = nil;
    
    NSLog(@"connectionDidFinishLoading");
    NSLog(@"%@",self.fullPath);
}

四. 文件上传

1.1 文件上传的步骤

设置请求头
[request setValue:@"multipart/form-data; boundary=分割线" forHTTPHeaderField:@"Content-Type"];

设置请求体
非文件参数
--分割线\r\n
Content-Disposition: form-data; name="参数名"\r\n
\r\n
参数值
\r\n

文件参数
--分割线\r\n
Content-Disposition: form-data; name="参数名"; filename="文件名"\r\n
Content-Type: 文件的MIMEType\r\n
\r\n
文件数据
\r\n

参数结束的标记
--分割线--\r\n

1.2 部分文件的MIMEType

类型文件拓展名MIMEType
图片pngimage/png
bmp\dibimage/bmp
jpe\jpeg\jpgimage/jpeg
gifimage/gif
多媒体mp3audio/mpeg
mp4\mpg4\m4vmp4vvideo/mp4
文本jsapplication/javascript
pdfapplication/pdf
text\txttext/plain
jsonapplication/json
xmltext/xml

1.3 获取MIMEType

// 利用NSURLConnection
- (NSString *)MIMEType:(NSURL *)url
{
    // 1.创建一个请求
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    // 2.发送请求(返回响应)
    NSURLResponse *response = nil;
    [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
    // 3.获得MIMEType
    return response.MIMEType;
}

C语言API
+ (NSString *)mimeTypeForFileAtPath:(NSString *)path
{
	if (![[NSFileManager alloc] init] fileExistsAtPath:path]) {
		return nil;
	}
    
	CFStringRef UTI = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)[path pathExtension], NULL);
    CFStringRef MIMEType = UTTypeCopyPreferredTagWithClass (UTI, kUTTagClassMIMEType);
    CFRelease(UTI);
	if (!MIMEType) {
		return @"application/octet-stream";
	}
    return NSMakeCollectable(MIMEType);
}

1.4 示例: 上传代码

#define Kboundary @"Boundary+E290ED5D8ABB1606"
#define KNewLine [@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]
- (void)postFromNetWork
{
    // 1.0 确定请求路径
    NSURL *url = [NSURL URLWithString:@"https://apitest3.drstrong.cn/health-doctor/feedback/uploadFeedbackImg"];
    
    // 2.0 创建可变请求对象
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
    
    // 2.1 修改请求方法,POST必须大写
    [request setHTTPMethod:@"POST"];
    
    // 2.2 设置属性, 请求超时
    request.timeoutInterval = 5;
    
    // 2.3 设置header
    [request setValue:@"990472e1ff8146fca638597f5f0e51d2" forHTTPHeaderField:@"token"];
    
    // 2.4设置请求的格式为上传类型
    [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",Kboundary] forHTTPHeaderField:@"Content-Type"];
    
    // 2.5 设置请求体
    // 2.5.1 文件参数
    NSMutableData *fileData = [NSMutableData data];
    /**
     --Boundary+E290ED5D8ABB1606
     Content-Disposition: form-data; name="file"; filename="imgFile"
     Content-Type: image/png
     
     @¿±:Ì=ºÃûNþ^-zêo¾ô¾gŠ—¿óď^zóO|çUýíB’
     ꆻ不^tOy咊®i^ot–“föכ󆉾/·Ð%§,Q[íóz³*Ó~^fÊ
     
     --Boundary+E290ED5D8ABB1606
     Content-Disposition: form-data; name="token"

     e8dc2e74694df8689089
     --Boundary+E290ED5D8ABB1606--
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@", Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine]; // 换行
    [fileData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=%@; filename=%@", @"file", @"imgFile"] dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine]; // 换行
    [fileData appendData:[@"Content-Type: image/png" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine]; // 换行
    [fileData appendData:KNewLine]; // 换行
    
    UIImage *image = [UIImage imageNamed:@"杭州盘石信息技术有限公司996制度.png"];
    NSData *imageData = UIImagePNGRepresentation(image);
    [fileData appendData:imageData];
    [fileData appendData:KNewLine]; // 换行
    
    /**
     2.5.2 非文件参数
     --Boundary+E290ED5D8ABB1606
     Content-Disposition: form-data; name="token"

     e8dc2e74694df8689089
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@", Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine]; // 换行
    [fileData appendData:[@"Content-Disposition: form-data; name=\"token\"" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine]; // 换行
    [fileData appendData:KNewLine]; // 换行
    [fileData appendData:[@"e8dc2e74694df8689089" dataUsingEncoding:NSUTF8StringEncoding]];
    [fileData appendData:KNewLine]; // 换行
    /**
     2.5.3 结尾标识
     --Boundary+E290ED5D8ABB1606--
     */
    [fileData appendData:[[NSString stringWithFormat:@"--%@--", Kboundary] dataUsingEncoding:NSUTF8StringEncoding]];
    
    
    // 2.6 设置请求体
    request.HTTPBody = fileData;
    
    
    // 3.0 异步请求
    NSURLConnection *connect = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
    
    [connect start];
}