NSURLSession/NSURLConnection File Upload method, nsurlsession upload Image
The best way to learn is understanding + understanding.
The theoretical basis of this article is mainly related to the HTTP network communication protocol. In order to concentrate, you can ignore the TCP/IP protocol, that is, focus only on the HTTP request and response structure. The complete principles of HTTP are omitted. Here, we will only mention the relevant content. The design Source Code involved in this article can be obtained here at https://github.com/wuqingjian2015/uploadhelper. you can check it if you are interested.
What is HTTP used?
Consider the following application process:
If you use the above process to upload files, you need:
The HTTP protocol solves these problems. It defines the Request body structure and response body structure. As long as the client or server complies with this standard, it can communicate with any application that complies with this standard.
If you want to observe what the HTTP-compliant request bodies and response bodies are "long", you can use some packet capture tools. I used Wireshark and Charles. For Web applications, press F12 on IE to bring up the network Tab of the development tool window.
Here, we only pay attention to the request and understand that the response StatusCode is 200, which indicates that it is normal.
For requests, because iOS will automatically set other content, if we do not set it. Here we will only discuss
How do I set the target address?Specify the URL when creating an NSURLRequest. For example,
NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL: self.tar getURL];
Next, we needSet the Content-Type ValueIs: multipart/form-data, and boundary value is also set, this boundary will be used when setting the Request body. So far, we have obtained such code:
-(NSURLRequest *) createRequestHeader
{
NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL: self.tar getURL]; // specify the target address
// Create an http header
// Content-Type: = multipart/form-data; boundary = --------------- 827292 (any)
// Content-Length: = (file Length)
NSString * contentType = [NSString stringWithFormat: @ "multipart/form-data; boundary = % @", self. boundary];
[Request setValue: contentType forHTTPHeaderField: @ "Content-Type"]; // set Content-Type
[Request setHTTPMethod: @ "post"]; // set Method to POST
Return request;
}
Next, let's see how to set the Request body. In iOS, it is specified by the NSURLRequest. HTTPBody attribute, which is of the NSData type.Remember:There is a fixed format. The format must be correct. Otherwise, the server cannot obtain the correct content. This problem cannot be reflected in the packet capture tool. As follows:
Format:
BeginBoundary
Content-Disposition: form-data; name = "<name required by the server>"; filename = "<name of the uploaded file on the server>"
Content-Type: application/zip -- select different values based on different file types
<Blank line>
<Binary data>
EndBoundary
Example:
---- KenApp299912318
Content-Disposition: form-data; name = "<name required by the server>"; filename = "<name of the uploaded file on the server>"
Content-Type: application/zip -- select different values based on different file types
<Blank line>
<Binary data>
---- KenApp299912318 --
Code has the truth:
-(NSData *) createDataForRequestHTTPBodyForSource
{
NSMutableString * bodyHead = [[NSMutableString alloc] init];
NSMutableData * data = [NSMutableData alloc] init];
NSString * fileName = [self. sourceURL lastPathComponent];
NSString * name = @ "uploadFile ";
NSData * fileContent = [NSData dataWithContentsOfURL: self. sourceURL];
// Create the http body request body content
// The first line: -- 827292
[BodyHead appendString: self. beginBoundary];
// [Body appendFormat: @ "--------------------"]
// Content-Disposition: form-data; name = "uploadFile"; filename = "xxxx. ext"
[BodyHead appendFormat: @ "Content-Disposition: form-data; name = \" % @ \ "; filename = \" % @ \ "\ r \ n", name, fileName];
// Content-Type: application/x-zip-compressed
// (Empty rows)
[BodyHead appendFormat: @ "Content-Type: application/zip \ r \ n"];
// (Binary data)
[Data appendData: [bodyHead dataUsingEncoding: NSUTF8StringEncoding];
[Data appendData: fileContent];
// Last line: 827292 --
[Data appendData: [self. endBoundary dataUsingEncoding: NSUTF8StringEncoding];
Return data;
}
So far, we know how to set the request header and request body. How can we use these results?
If NSURLConnection is used, we need to set the two in the same NSURLRequest.
Call factory method again[NSURLConnection connectionWithRequest: delegate:];
If you use uploadTask in NSURLSession, you need to set the Request Header (the following requestWithHeader) in NSURLRequest, and set the Request body (the following requestHTTPBody) in NSData ). The code example is as follows. SSUploadHelper encapsulates the process mentioned above.
//// // Example ///// ///////////////////
SSUploadHelper * uploadHelper = [[SSUploadHelper alloc] initWithTarget: [NSURL URLWithString: @ "http: // 192.168.31.172: 5012/ArchFlow/upload"] forSource: self. downloadedLocation];
NSURLSessionUploadTask * uploadTask = [self. response handler: [uploadHelper requestWithHeader] fromData: [uploadHelper requestHTTPBody] completionHandler: ^ (NSData * _ Nullable data, Handler * _ Nullable response, NSError * _ Nullable error ){
NSLog (@ "Got response % @ with error % @. \ n", response, error );
NSLog (@ "DATA: \ n % @ \ nEND DATA \ n ",
[[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]);
}];
[UploadTask resume];
//////////////////////////////////
So far, the client design is basically complete. To view the uploaded files on the server side, we need to build a server environment. I personally implemented a Python-based REST microserver. In the POST request for processing ArchFlow/upload, I obtained the file from the request and saved it to the local directory. This is the tool server I used in the software architecture. On this basis, the temporary file upload function is implemented.
// Function test:
When the server is started, run the above client code and you can see that the file is copied to the target directory.
Note:
The boundary format is worth noting that the boundary specified in the request header must be in the Request body.
The rest is patience debugging. Good Luck!