iOS上传文件,有关http上传协议

时间:2021-08-04 20:29:59

iOS上传文件,有关http上传协议

以上是抓包HTML input file标签上传的内容

只要模拟上面http 的header跟body就可以成功。

整体说明:

post 上传文件时,以在http body里面带参数,参数的格式,根据RFC1867协议要求写成如下

在http header 里面定义 boundary ,boundary的值为body里面分隔参数的标志。

Content-Type: multipart/form-data; boundary=----------LlcUploadTaskWithRequest

假设 post 过去,两个参数 user="loganv"&pwd="123456" 跟一个二进制文件 file,服务端通过字段 'file' 获取文件流,文件名字叫做filename.png。

------------LlcUploadTaskWithRequest
Content
-Disposition: form-data; name="user"

loganv------------LlcUploadTaskWithRequest
Content
-Disposition: form-data; name="pwd"

123456------------LlcUploadTaskWithRequest
Content
-Disposition: form-data; name="file"; filename="filename.png"
Content
-Type: application/octet-stream

ÿØÿàJFIFHHÿá¼ExifMM
*JR(‡i(此处为上传的二进制文件数据)
把下面这个体当成一对整体来看
------------LlcUploadTaskWithRequestContent-Disposition: form-data; name="user"

loganv

第一行:以header 里面定义的 boundary的值,在前面加"--",,以"\r\n"结尾

第二行:定义了参数的键 user ,以"\r\n"结尾

第三行:"\r\n"

第四行:参数的值 123456,以"\r\n"结尾

如果参数是文件,需要在上面的低二行下面增加一行定义文件的类型 MIME type

 

iOS 实现上传,swift2.0 主要代码

第一步:自定义boundary分割标志,在给header加个 Content-Type;

let post_boundary = "----------LlcUploadTaskWithRequest"

let reqq = NSMutableURLRequest(URL: NSURL(string: "http://172.16.0.199/upload/uploadIpa.php")!)

reqq.HTTPMethod = "POST"

reqq.setValue(post_boundary, forHTTPHeaderField: "Content-Type")

第二步:拼接http body 需要 post 过去的参数,跟二进制文件;服务端通过字段 'file' 获取文件流;

let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
var paramStr = ""

        if param != nil{

            for (k, v) in param!{

                paramStr += uploadPostParamInBody(k, nameValue: v.description)

            }

        }

        paramStr += uploadPostParamInBody("file", filename: "filename.png")

        let boundary = paramStr.dataUsingEncoding(NSUTF8StringEncoding)?.mutableCopy() as? NSMutableData

        let pdata = NSData(data: multipartFormData!)

        let boundary_end = ("\r\n--" + post_boundary + "--").dataUsingEncoding(NSUTF8StringEncoding)

        boundary?.appendData(pdata)

        boundary?.appendData(boundary_end!)

拼接参数的方法

//---- uploadTaskWithRequest 上传
/*
name: post body里面带的参数的名称,服务器根据这个名称取得对应的参数值;
filename: 文件的名字比如 logo.png;
MIMEtyp: 为application/octet-stream代表任何二进制流都可以,图片传image/jpeg;

*/
public func uploadPostParamInBody(name: String, filename: String = "", nameValue: String = "", MIMEtype: String = "application/octet-stream") -> String{
var content
= "--" + LlcHttpRequest.post_boundary + "\r\n"
if filename == ""{
content
+= "Content-Disposition: form-data; name=\"\(name)\"\r\n\r\n";
content
+= "\(nameValue)\r\n";
}
else{
content
+= "Content-Disposition: form-data; name=\"\(name)\"; filename=\"\(filename)\"\r\n";
content
+= "Content-Type: \(MIMEtype)\r\n\r\n";
}
return content
}

第三步:请求

let task = session.uploadTaskWithRequest(req.request, fromData: boundary){
(obj: NSData
?, resp: NSURLResponse?, err: NSError?) -> Void in
if let respHtml = resp as? NSHTTPURLResponse {
if respHtml.statusCode == 200 {
if obj != nil{
var resu: AnyObject
? = String(data: obj!, encoding: NSUTF8StringEncoding)
if let json = try? NSJSONSerialization.JSONObjectWithData(obj!, options: .AllowFragments){
resu
= json
}
}

}

}
else{
fail(resp: resp, error: err)
}
if err != nil{
fail(resp: resp, error: err)
}
}
task.resume()

完了!

 

附上PHP服务端简单接受文件上传的代码

<?php


$text
= isset($_REQUEST['text']) ? $_REQUEST['text'] : "";
echo
'success<br>';
if ($_FILES["file"]["error"] > 0){
echo
"Error: " . $_FILES["file"]["error"] . "<br />";
}
elseif ($_FILES[
"file"]["size"] > 20*1024*1024) {
echo
'file too big';
}
else{
echo
"Upload: " . $_FILES["file"]["name"] . "<br />";
echo
"Type: " . $_FILES["file"]["type"] . "<br />";
echo
"Size: " . ($_FILES["file"]["size"] / 1024) . " Kb<br />";
echo
"Stored in: " . $_FILES["file"]["tmp_name"] . '<br />';

$isipa
= false;
$uploadSrc
= '../download/ipa/'.$_FILES["file"]["name"];
if ( preg_match('/\.ipa$/', $_FILES["file"]["name"]) ) {
$isipa
= true;
$uploadSrc
= '../download/ipa/'.'test01.ipa';
}

if (file_exists($uploadSrc) && $isipa ){
// echo $_FILES["file"]["name"] . " already exists. ";
rename($uploadSrc, '../download/ipa/'.date('Y-m-d H:i:s').'.ipa');
}
move_uploaded_file($_FILES[
"file"]["tmp_name"], $uploadSrc);
echo
"Stored in: " . $uploadSrc.'<br>';
echo
'上传成功!';
}