简介

上传文件到服务器是一个比较常用的操作,最基本的方式是通过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. 注意类型转换——Effective C++

    注意类型转换: C++提供了四种新式类型转换: const_cast<T>(expression); static_cast<T>(expression); dynamic_c ...

  2. 51nod 1514 美妙的序列

    Description 长度为n的排列,且满足从中间任意位置划分为两个非空数列后,左边的最大值>右边的最小值.问这样的排列有多少个%998244353 题面 Solution 正难则反 \(f[ ...

  3. ●BZOJ 1531 [POI2005]Bank notes

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=1531 题解: 单调队列优化多重背包DP (弱弱的我今天总算是把这个坑给填了...) 令V[i ...

  4. ●CodeForces 280D k-Maximum Subsequence Sum

    题链: http://codeforces.com/problemset/problem/280/D 题解: 神题,巨恶心.(把原来的那个dp题升级为:序列带修 + 多次询问区间[l,r]内取不超过k ...

  5. 【bzoj4569 scoi2016】萌萌哒

    题目描述 一个长度为n的大数,用S1S2S3...Sn表示,其中Si表示数的第i位,S1是数的最高位,告诉你一些限制条件,每个条件表示为四个数,l1,r1,l2,r2,即两个长度相同的区间,表示子串S ...

  6. 新版Eclipse打开jsp、js等为文本编辑,没有JSP Editor插件问题

    刚从官网下载安装的Eclipse Java Oxygen.2但是打开的jsp文件尽然默认文本编辑器打开,就js文件也是一样,纳闷! 网上搜索一番,原来缺少web开发相关工具, 下面给插件安装方法: 1 ...

  7. java集合之LinkedList源码解读

    源自:jdk1.8.0_121 LinkedList继承自AbstractSequentialList,实现了List.Deque.Cloneable.Serializable. LinkedList ...

  8. Java 反射 Method threw 'java.lang.InstantiationException' exception.

    查看这个InstantiationException:异常的api所说的是: 当应用程序试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象无法被实例化时,抛出该 ...

  9. 用一个div模拟textarea的实现

    <textarea> 标签定义一个多行的文本输入控件.但是它不能像div一样随着内容增加而自动增加,一言不合就出现滚动条,有是有为了更好的交互,可能需要使用div来模拟textarea的实 ...

  10. Python小代码_1_九九乘法表

    Python小代码_1_九九乘法表 max_num = 9 row = 1 while row <= max_num: col = 1 while col <= row: print(st ...