(一二八)使用POST上传文件

简介

上传文件到服务器是一个比较常用的操作,最基本的方式是通过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

转载于:https://www.cnblogs.com/aiwz/p/6154026.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值