zoukankan      html  css  js  c++  java
  • iOS上传文件,有关http上传协议-RFC1867

    以上是抓包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(此处为上传的二进制文件数据)
    把下面这个体当成一对整体来看
    ------------LlcUploadTaskWithRequest Content-Disposition: form-data; name="user" loganv

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

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

    第三行:" "

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

    如果参数是文件,需要在上面的低二行下面增加一行定义文件的类型 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 = (" --" + 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 + "
    "
            if filename == ""{
                content += "Content-Disposition: form-data; name="(name)"
    
    ";
                content += "(nameValue)
    ";
            }
            else{
                content += "Content-Disposition: form-data; name="(name)"; filename="(filename)"
    ";
                content += "Content-Type: (MIMEtype)
    
    ";
            }
            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 '上传成功!';
      }
  • 相关阅读:
    Selector + 线程池 遇到的问题
    【转】Android TabActivity无法正常bindService解决方法
    Android 中的 Service 全面总结
    【转】IT 圈里有哪些经常被读错的词?
    【转】线程的7种状态及相互转换
    【eoeandroid 特刊】第117期打包网盘下载地址
    使用 Android 自带的 proguard 混淆源码
    Google+ 连接不上的解决办法
    【转】AsyncTask的用法
    winForm简单数据绑定
  • 原文地址:https://www.cnblogs.com/loganv/p/4920741.html
Copyright © 2011-2022 走看看