简介

上传文件到服务器是一个比较常用的操作,最基本的方式是通过POST上传,文件以二进制形式,作为一个参数传递,但是这个POST的结构相当复杂,且必须完全符合HTTP标准。

文件上传的POST格式

该POST主要由下面几个部分构成。

  • 请求头

    1.Content-Length(请求体的二进制大小)

    • 注意这里的二进制大小应该根据请求体计算

    2.Content-Type multipart/form-data; boundary=(分隔符)

    • 注意这里的分隔符与请求体的分隔符有关,但不完全一致。
  • 请求体

    基本格式示例

    • 这里的分隔符就是上面的分隔符,但是前面要多加两个'-'
    --分隔符
    Content-Disposition: form-data; name="uploadFile"; filename="button.png"
    Content-Type: image/png
    (此处空两行)
    <二进制内容>
    --分隔符
    Content-Disposition: form-data; name="submit"
    (此处空两行)
    Submit
    --分隔符--
    (此处空一行)
    • 注意到最后的分隔符后面跟了--,这个代表结束符,并且后面要跟一个空行。

    格式说明

    • 普通参数

      普通参数的构成如下:

      Content-Disposition: form-data; name="参数名"
      (此处空两行)
      参数值
      --分隔符

      多个参数可以连续拼接。

    • 文件参数

      文件参数与普通参数类似,只是多了一行MineType的说明,该说明告诉服务器文件的类型。

      Content-Disposition: form-data; name="uploadFile"; filename="button.png"
      Content-Type: image/png
      (此处空两行)
      <二进制内容>
      --分隔符

    将二者连起来就构成了完整的文件上传POST信息,到这里我们可以理解,该POST不仅发送了文件数据,还发送了一个参数。

文件上传的服务器php脚本

  • 要让post请求发挥作用,必须借助php脚本实现对post的处理,换句话说,我们的post请求应该发送给该php脚本,脚本的代码如下:(注意修改uploadPath为自己服务器想要接收文件的路径)

    <?php
    header("Content-type: text/html; charset=utf-8");
    // 配置文件需要上传到服务器的路径,需要允许所有用户有可写权限,否则无法上传!
    $uploadPath = '../uploads/'; $IOS_forKey=$_FILES["uploadFile"]; if ($IOS_forKey["error"] > 0) {
    echo "传入参数错误:" . $IOS_forKey["error"] . "<br />";
    } else {
    echo "文件: " . $IOS_forKey["name"] . "<br />";
    echo "类型: " . $IOS_forKey["type"] . "<br />";
    echo "大小: " . ($IOS_forKey["size"] / 1024) . " Kb<br />";
    echo "临时文件: " . $IOS_forKey["tmp_name"] . "<br />"; chmod($uploadPath . $IOS_forKey["name"], 0666);
    if (file_exists($uploadPath . $IOS_forKey["name"])) {
    echo $IOS_forKey["name"] . "文件已经存在!";
    } else {
    move_uploaded_file($IOS_forKey["tmp_name"], $uploadPath . $IOS_forKey["name"]);
    echo "上传文件保存在: " . $uploadPath . $IOS_forKey["name"];
    }
    }
    ?>

通过iOS设备上传文件

想要通过iOS设备上传文件,一般的做法是根据上面的结构创建URLRequset,然后发送该request到服务器请求上面的php脚本,实现文件的上传,具体的代码如下。

  • 为了方便插入二进制文件数据,我们直接使用data拼接,因此对于每一段字符串都需要转为data,这就是DataWithStr宏的作用。

  • 为了适配各个系统的换行符,使用\r\n。

  • FileBoundary就是上文提到的分隔符。

  • HTTP请求头的contentLength需要待请求体拼接完毕后才能得到,因此最后才赋值。

#import "ViewController.h"
#import "UploadFile.h" #define FileBoundary @"-----------------------------test"
#define EndLine @"-----------------------------test--\r\n"
#define NewLine @"\r\n"
#define DataWithStr(str) [str dataUsingEncoding:NSUTF8StringEncoding] @interface ViewController () @end @implementation ViewController - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ [self upload]; } - (void)upload{ NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://127.0.0.1/lesson2/upload.php"]];
request.HTTPMethod = @"POST";
// 设置请求头
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",FileBoundary];
[request setValue:contentType forHTTPHeaderField:@"Content-Type"];
// 设置请求体
NSMutableData *body = [NSMutableData data];
[body appendData:DataWithStr(@"--")];
[body appendData:DataWithStr(FileBoundary)];
[body appendData:DataWithStr(NewLine)];
[body appendData:DataWithStr(@"Content-Disposition: form-data; name=\"uploadFile\"; filename=\"test.png\"")];
[body appendData:DataWithStr(NewLine)];
[body appendData:DataWithStr(@"Content-Type: image/png")];
[body appendData:DataWithStr(NewLine)];
[body appendData:DataWithStr(NewLine)]; UIImage *img = [UIImage imageNamed:@"test.png"];
NSData *imgData = UIImagePNGRepresentation(img);
[body appendData:imgData];
[body appendData:DataWithStr(NewLine)]; // 其他参数
[body appendData:DataWithStr(@"--")];
[body appendData:DataWithStr(FileBoundary)];
[body appendData:DataWithStr(@"Content-Disposition: form-data; name=\"param1\"")];
[body appendData:DataWithStr(NewLine)];
[body appendData:DataWithStr(NewLine)];
[body appendData:DataWithStr(@"value1")];
[body appendData:DataWithStr(NewLine)];
[body appendData:DataWithStr(@"--")];
[body appendData:DataWithStr(EndLine)]; [request setValue:[NSString stringWithFormat:@"%ld",body.length] forHTTPHeaderField:@"Content-Length"]; request.HTTPBody = body; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@",result);
}]; } @end

(一二八)使用POST上传文件的更多相关文章

  1. IE8/9 JQuery.Ajax 上传文件无效

    IE8/9 JQuery.Ajax 上传文件有两个限制: 使用 JQuery.Ajax 无法上传文件(因为无法使用 FormData,FormData 是 HTML5 的一个特性,IE8/9 不支持) ...

  2. 三种上传文件不刷新页面的方法讨论:iframe/FormData/FileReader

    发请求有两种方式,一种是用ajax,另一种是用form提交,默认的form提交如果不做处理的话,会使页面重定向.以一个简单的demo做说明: html如下所示,请求的路径action为"up ...

  3. asp.net mvc 上传文件

    转至:http://www.cnblogs.com/fonour/p/ajaxFileUpload.html 0.下载 http://files.cnblogs.com/files/fonour/aj ...

  4. app端上传文件至服务器后台,web端上传文件存储到服务器

    1.android前端发送服务器请求 在spring-mvc.xml 将过滤屏蔽(如果不屏蔽 ,文件流为空) <!-- <bean id="multipartResolver&q ...

  5. .net FTP上传文件

    FTP上传文件代码实现: private void UploadFileByWebClient() { WebClient webClient = new WebClient(); webClient ...

  6. 通过cmd完成FTP上传文件操作

    一直使用 FileZilla 这个工具进行相关的 FTP 操作,而在某一次版本升级之后,发现不太好用了,连接老是掉,再后来完全连接不上去. 改用了一段时间的 Web 版的 FTP 工具,后来那个页面也 ...

  7. 前端之web上传文件的方式

    前端之web上传文件的方式 本节内容 web上传文件方式介绍 form上传文件 原生js实现ajax上传文件 jquery实现ajax上传文件 form+iframe构造请求上传文件 1. web上传 ...

  8. Django session cookie 上传文件、详解

    session 在这里先说session 配置URL from django.conf.urls import patterns, include, url from django.contrib i ...

  9. 4 django系列之HTML通过form标签来同时提交表单内容与上传文件

    preface 我们知道提交表单有2种方式,一种直接通过submit页面刷新方法来提交,另一种通过ajax异步局部刷新的方法提交,上回我们说了通过ajax来提交文件到后台,现在说说通过submit来提 ...

随机推荐

  1. [HNOI 2010]chorus 合唱队

    Description 题库链接 对于一个包含 \(N\) 个整数的数列 \(A\) ,我们可以把它的所有元素加入一个双头队列 \(B\) . 首先 \(A_1\) 作为队列的唯一元素,然后依次加入 ...

  2. [Luogu 1410]子序列

    Description 给定一个长度为N(N为偶数)的序列,问能否将其划分为两个长度为N/2的严格递增子序列, Input 若干行,每行表示一组数据.对于每组数据,首先输入一个整数N,表示序列的长度. ...

  3. 3064: Tyvj 1518 CPU监控

    注意这题要维护历史最大加和历史最大覆盖 /************************************************************** Problem: 3064 Us ...

  4. poj 2104 主席树(区间第k大)

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 44940   Accepted: 14946 Ca ...

  5. 用Qemu运行/调试arm linux【转】

    转自:https://blog.csdn.net/absurd/article/details/78984244 用Qemu运行/调试arm linux,这事情干过好几次了,久了就忘记了,每次都要重新 ...

  6. SQL优化实用方法

    SQL优化:避免索引失效 1.不使用NULL 任何在where子句中使用is null或is not null的语句优化器是不允许使用索引的.因为只有该字段中有null值,即使创建了索引其实也是没有用 ...

  7. salesforce lightning零基础学习(二) lightning 知识简单介绍----lightning事件驱动模型

    看此篇博客前或者后,看一下trailhead可以加深印象以及理解的更好:https://trailhead.salesforce.com/modules/lex_dev_lc_basics 做过cla ...

  8. oracle之子查询、创建用户、创建表、约束

      子查询                                    子查询可以分为单行子查询和多行子查询   单行子查询           [1] 将一个查询的结果作为另外一个查询的条 ...

  9. spring的@Transactional(rollbackFor=Exception.class)的使用

    Spring框架的事务基础架构代码将默认地只在抛出运行时和unchecked exceptions时才标识事务回滚. 也就是说,当抛出个RuntimeException 或其子类例的实例时.(Erro ...

  10. JSTL标签四种判断语句的用法

    一.条件运算符 ${user.gender==1?'男':'女'} 二.if() <c:if test="${2>1}">code..</c:if> ...