iOS开发之NSURLSessionUploadTask上传数据

作者: YungFan | 来源:发表于2017-03-10 19:22 被阅读356次

    苹果在 iOS9 之后已经废弃了NSURLConnectionNSURLSession成为其替代者,其基本知识网上很多,主要可以从NSURLSessionDataTaskNSURLSessionDownloadTaskNSURLSessionUploadTask入手学习。最近在写案例时发现其中的NSURLSessionUploadTask还是有着不少的坑,在开发时有时候很难一次性成功。所以将研究的过程记录与分享一下。我会以一个完整的案例来讲解如何使用。

    服务器开发

    环境:IDEA 14 +Tomcat 8.x+JDK 8

    1、编写服务器端代码
    由于上传数据与下载数据不同,下载的时候只要把数据丢进服务器就可以了。但是上传需要服务器自己来处理。所以以Java Servlet来写服务器端,由于Servlet 3.0 以后可以直接处理文件上传,所以相对比较简单,代码如下,注释很详细。

    import javax.servlet.ServletException;
    import javax.servlet.annotation.MultipartConfig;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.Part;
    import java.io.File;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    @MultipartConfig //标识Servlet支持文件上传
    public class UploadServlet extends HttpServlet {
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            //存储路径为我们的根目录
            String storePath = req.getServletContext().getRealPath("/");
            //获取part对象,参数为客户端表单中的name属性的值
            Part part = req.getPart("myfile");
            //Servlet3没有提供直接获取文件名的方法,需要从请求头中解析出来
            //获取请求头
            String header = part.getHeader("Content-Disposition");
            //获取文件名
            String fileName = header.substring(header.lastIndexOf("=") + 2, header.length() - 1);
            //把文件写到指定路径
            part.write(storePath + File.separator + fileName);
            //回写数据给客户端
            resp.setCharacterEncoding("UTF-8");
            PrintWriter pw = resp.getWriter();
            pw.print("上传成功");
        }
    
    }
    

    2、部署代码
    找到Tomcat根目录下的conf文件夹,打开server.xml,在最后加上一行代码,path就是访问的项目路径,docBase就是项目编译后的位置。

    <Context path="/AppTestAPI" docBase="E:\AppTestAPI\out\artifacts\AppTestAPI" auth="Container" /> 
    

    3、启动服务器
    通过浏览器访问http://localhost能出现如下的界面,至此完成服务器端工作。( 由于我修改了默认端口,所以没有加8080 )

    Paste_Image.png

    客户端开发

    环境:Xcode 7.3.1

    1、创建项目
    创建一个项目,布置界面,设置支持http网络访问。主界面如下:

    界面.png

    2、编写代码
    NSURLSession使用都是一个套路:创建请求,创建任务,执行任务,成功回调。但是在使用NSURLSessionUploadTask进行上传时最麻烦的是上传数据的构造,其遵循严格的规范,如下图,不能随意书写,不能随意书写,不能随意书写~,重要的事情说三遍,否则坑得你生活不能自理。

    上传必填字段.png

    下面是ViewController的代码,其中最核心的是getData方法。

    #import "ViewController.h"
    
     //分隔符
    #define YFBoundary @"AnHuiWuHuYungFan"
    //换行
    #define YFEnter [@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]
    //NSString转NSData
    #define YFEncode(string) [string dataUsingEncoding:NSUTF8StringEncoding]
    
    @interface ViewController ()<NSURLSessionTaskDelegate>
    
    @property (weak, nonatomic) IBOutlet UIProgressView *uploadProgress;
    @property (weak, nonatomic) IBOutlet UILabel *uploadInfo;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        //1、确定URL
        NSURL *url = [NSURL URLWithString:@"http://192.168.0.5/AppTestAPI/UploadServlet"];    
        //2、确定请求
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];  
        //3、设置请求头
        NSString *head = [NSString stringWithFormat:@"multipart/form-data;boundary=%--@", YFBoundary];
        [request setValue:head forHTTPHeaderField:@"Content-Type"];
        //4、设置请求方式,上传时必须是Post请求
        request.HTTPMethod = @"POST";
        //5、创建NSURLSession
        NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
        //6、获取上传的数据
        NSData *uploadData = [self getData];
        //7、创建上传任务 上传的数据来自getData方法
        NSURLSessionUploadTask *task = [session uploadTaskWithRequest:request fromData:uploadData completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
            
           //上传成功以后改变UILabel文本为服务器返回的数据
           self.uploadInfo.text =[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
        
        }];
        //8、执行上传任务
        [task resume];
        
    }
    
    
    /**
     *  设置请求体
     *
     *  @return 请求体内容
     */
    -(NSData *)getData
    {
    
        NSMutableData *data = [NSMutableData data];
        
        //1、开始标记
        //--
        [data appendData:YFEncode(@"--")];
        //boundary
        [data appendData:YFEncode(YFBoundary)];
        //换行符
        [data appendData:YFEnter];
        //文件参数名 Content-Disposition: form-data; name="myfile"; filename="wall.jpg"
        [data appendData:YFEncode(@"Content-Disposition:form-data; name=\"myfile\"; filename=\"wall.jpg\"")];
        //换行符
        [data appendData:YFEnter];
        //Content-Type 上传文件的类型 MIME
        [data appendData:YFEncode(@"Content-Type:image/jpeg")];
        //换行符
        [data appendData:YFEnter];
        //换行符
        [data appendData:YFEnter];
        //2、上传的文件数据
        
        //图片数据  并且转换为Data
        UIImage *image = [UIImage imageNamed:@"wall.jpg"];
        NSData *imagedata = UIImageJPEGRepresentation(image, 1.0);
        [data appendData:imagedata];
        //换行符
        [data appendData:YFEnter];
     
        //3、结束标记
        //--
        [data appendData:YFEncode(@"--")];
        //boundary
        [data appendData:YFEncode(YFBoundary)];
        //--
        [data appendData:YFEncode(@"--")];
        //换行符
        [data appendData:YFEnter];
        
        return data;
        
    }
    
    #pragma mark - 代理方法 只要给服务器上传数据就会调用 可以计算出上传进度
    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesSent totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
    {
    
        //设置进度条
        self.uploadProgress.progress = 1.0 * totalBytesSent / totalBytesExpectedToSend;
    }
    
    @end
    
    

    最终效果

    先看客户端的表象

    客户端演示.gif

    再看服务器端最终上传的数据,不重要以为是图片,静静观察一会儿~~~有变化

    服务器端.gif

    相关文章

      网友评论

      • 简书lu:为什么要设置那么多的换行、
        YungFan:@简书lu Http的规范
      • NOW_GO:我看到了未来的大牛😛,帆哥
        YungFan:@坚持_0109 :scream::scream::scream:

      本文标题:iOS开发之NSURLSessionUploadTask上传数据

      本文链接:https://www.haomeiwen.com/subject/wzrogttx.html