1. 程式人生 > >如何使用objective c上傳檔案,用flask接收檔案

如何使用objective c上傳檔案,用flask接收檔案

flask是python中類似於php的伺服器元件。

ios提供了NSMutableArray和 dataTaskWithRequest用來使用http上傳資料。但是flask只支援基於表單格式的資料。

表單格式是在原始http資料上,提供了額為的資訊。如果直接使用ios的api把資料傳送給flask,是收不到資訊的,也就是request物件裡的files為空。

五花八門的傳送方式(web,ajex,form,c等等),各種各樣的接收方式(php,java,flask等)讓這個問題感覺很繁雜。為了解決這個問題,需要理解html裡面post的原理。

post和get是html中,在客戶端和服務端傳輸資料的兩種方式,這裡只講post。

post有三種類型:

  • application/x-www-form-urlencoded (the default)
    • 由key和value對組成的文字格式
  • multipart/form-data
    • 更為複雜的格式,允許二進位制資料,這也是傳輸二進位制檔案的唯一格式
  • text/plain
    • 原始文字,一般不用
POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: application/x-www-form-urlencoded
Content-Length: 51
text1=text+default&text2=a%CF%89b&file1=a.txt&file2=a.html&file3=binary
POST / HTTP/1.1
[[ Less interesting headers ... ]]
Content-Type: multipart/form-data; boundary=%%%%%%%%%%%%%%%%%%%%%
Content-Length: 834
%%%%%%%%%%%%%%%%%%%%%
Content-Disposition: form-data; name="text1"
text default
%%%%%%%%%%%%%%%%%%%%%
Content-Disposition: form-data; name="text2"
aωb
%%%%%%%%%%%%%%%%%%%%%
Content-Disposition: form-data; name="file1"; filename="a.txt"
Content-Type: text/plain
Content of a.txt.
%%%%%%%%%%%%%%%%%%%%%
Content-Disposition: form-data; name="file2"; filename="a.html"
Content-Type: text/html
<!DOCTYPE html><title>Content of a.html.</title>
%%%%%%%%%%%%%%%%%%%%%
Content-Disposition: form-data; name="file3"; filename="binary"
Content-Type: application/octet-stream
aωb
%%%%%%%%%%%%%%%%%%%%%

Content-Type是兩種方式都需要有的,

NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",@"%%%%%%%%%%%%%%%%%%%%%"];
[request setValue:contentType forHTTPHeaderField:@"Content-Type"];

通過此方法可以設定這個部分。

[request setValue:[NSString stringWithFormat:@"%lu",data.length] forHTTPHeaderField:@"Content-Length"];

通過此方法可以設定長度。 

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";

設定是POST和是GET

對於application/x-www-form-urlencoded ,在設定完Content-Type後,直接設定字典型的文字內容就行。

request.HTTPBody = text1=text+default&text2=a%CF%89b&file1=a.txt&file2=a.html&file3=binary;

對於multipart/form-data的HTTPBody部分比較複雜。

NSMutableString *headerStrM =[NSMutableString string];
[headerStrM appendFormat:@"--%@\r\n",@"boundary"];
[headerStrM appendFormat:@"Content-Disposition: form-data; name=%@; filename=%@\r\n",formName,reName];
[headerStrM appendFormat:@"Content-Type: %@\r\n\r\n",fileType];
[data appendData:[headerStrM dataUsingEncoding:NSUTF8StringEncoding]];
NSData *fileData = [NSData dataWithContentsOfFile:filePath];
[data appendData:fileData];
NSMutableString *footerStrM = [NSMutableString stringWithFormat:@"\r\n--%@--\r\n",@"boundary"];
[data appendData:[footerStrM  dataUsingEncoding:NSUTF8StringEncoding]];

HTTPBody可以儲存多種型別資料,所以叫做multipart。

每個資料之間用設定的boundary來分割boundary=%%%%%%%%%%%%%%%%%%%%%

Content-Disposition: form-data; name="file1"; filename="a.txt" 設定了這部分資料的屬性,name對應flask request中files字典中的key值。要得到"a.txt"這個檔名,在flask可以通過request.files.file.filename

Content-Types是用於服務端自動根據上傳的資料做不同的處理,如果是自己寫程式接收資料的話,這裡可以是任意自定義的字串。

flask詳細程式碼見:https://github.com/rabienrose/ros_ios_chamo/blob/master/server/server.py

如果使用最原始的http api的話,要讓就需要自己按照上述規則生成對應資料,傳送給flask,flask就可以解析成對應的格式了。