向本地的apache服务器上传文件

上传文件


上传单个文件

  • 通过火狐浏览器中的Firebug插件,可以查看浏览器发送的数据包内容

向本地的apache服务器上传文件_第1张图片

向本地的apache服务器上传文件_第2张图片

//上传单个文件的数据包内容解析:
// 请求头
Content-Type
multipart/form-data; boundary=itheima //-boundary分隔符,可以是任意字符和数字的组合,但是不能包含中文.


// 请求体(就是向服务器发送的数据,类型为NSData)
--itheima //根据上面请求头中的boundary设置的边界标识来分隔开请求体
Content-Disposition: form-data; name="userfile"; filename="abc.txt"
Content-Type: text/plain

11111111111111
1111111111111
111111111111
1111111111

--itheima--

//name:服务器接收文件数据对应的字段名
//filename:上传数据保存到服务器使用的文件名
//Content-Type: text/plain表示上传文件是文本数据

*********************下面是更为具体的解释*********************

    name:服务器上传文件的字段名称,可以找公司后台要
    filename:保存到服务器上的文件名,通常不允许重复,但是后端脚本会处理。
    Content-Type:告诉服务器当前文件的类型(MIMEType),一般划分格式为:
    大类型/小类型
    text/plain  纯文本
    text/html   html文件
    text/xml    xml文件
    image/png
    image/gif
    image/jpg
    application/json
    application/octet-stream 任意的二进制数据
    ........
    如果不知道填什么,百度下就行了,没必要死记。

具体实现代码

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    // 读取文件数据
    NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"abc.txt" ofType:nil]];
    // 上传文件
    [self uploadFile:data fieldName:@"userfile" fileName:@"bbb.txt"];
}


#define HMBoundary @"itheima"
- (void)uploadFile:(NSData *)fileData fieldName:(NSString *)fieldName fileName:(NSString *)fileName{
    // 负责处理上传文件的PHP脚本文件的URL(要先将该脚本文件放到apache服务器中)
    NSURL *url = [NSURL URLWithString:@"http://localhost/post/upload.php"];

    // 可变的Request,因为需要修改默认的参数,如请求方法,请求头等内容
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    // 设置请求方法
    request.HTTPMethod = @"POST";
    // 设置请求头:告诉服务器客户端是做文件上传操作
    [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",HMBoundary] forHTTPHeaderField:@"Content-Type"];
    // 设置请求体
    request.HTTPBody = [self fileData:fileData fieldName:fieldName fileName:fileName];

    // 发送请求,上传文件
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        //读取从服务器返回的JSON数据
        NSLog(@"%@--%@",response,[NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]);
    }];
}

/**
 *  拼接请求体内容
 *
 *  @param fileData  要上传文件的二进制数据
 *  @param fieldName 服务器接收文件数据的使用的字段名(找服务器开发人员要)
 *  @param fileName  保存服务器使用的文件名
 */

/*
 --itheima \r\n
 Content-Disposition: form-data; name="userfile"; filename="abc.txt" \r\n
 Content-Type: application/octet-stream \r\n\r\n

 上传文件的二进制数据
 \r\n--itheima--
 */
- (NSData *)fileData:(NSData *)fileData fieldName:(NSString *)fieldName fileName:(NSString *)fileName{
    NSMutableData *dataM = [NSMutableData data];
    // 创建可变字符串用来评价请求体内容
    // 换行符是\r\n
    NSMutableString *strM = [NSMutableString stringWithFormat:@"--%@\r\n",HMBoundary];
    [strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\" \r\n",fieldName,fileName];
    [strM appendString:@"Content-Type: application/octet-stream \r\n\r\n"];

    // 将上面的字符串以UTF-8编码后拼接到dataM中(字符串类型转NSdata类型)
    [dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]];

    // 拼接文件的二进制数据
    [dataM appendData:fileData];

    // 结尾标记
    NSString *tail = [NSString stringWithFormat:@"\r\n--%@--",HMBoundary];
    // 将结尾标记字符串拼接到dataM后面
    [dataM appendData:[tail dataUsingEncoding:NSUTF8StringEncoding]];

    return dataM;
}

@end

上传多个文件

  • 用PHP脚本上传两个文件,查看发送的数据格式

向本地的apache服务器上传文件_第3张图片

  • 通过火狐浏览器中的Firebug插件,可以查看浏览器发送的数据包内容

向本地的apache服务器上传文件_第4张图片

向本地的apache服务器上传文件_第5张图片


//上传单个文件的数据包内容解析:
// 请求头
Content-Type
multipart/form-data; boundary=itheima //-boundary分隔符,可以是任意字符和数字的组合,但是不能包含中文


//上传两个文件的请求体,多个文件以此类推
--itheima\r\n
Content-Disposition: form-data; name="userfile[]"; filename="xxxx.txt"\r\n
Content-Type: text/plain\r\n\r\n

//上传文件1的二进制数据\r\n
11111111111111
1111111111111
111111111111
1111111111

--itheima\r\n
Content-Disposition: form-data; name="userfile[]"; filename="abc.txt"\r\n
Content-Type: text/plain\r\n\r\n

//上传文件2的二进制数据\r\n
222222222
222222222
222222222
22222222
2222

 --itheima\r\n
 Content-Disposition: form-data; name="username"\r\n\r\n

 //用户名\r\n
 rose
 --itheima--

具体代码实现

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    // 加载文件数据
    NSData *fileData1 = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"abc.txt" ofType:nil]];
    NSData *fileData2 = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"aaaa.png" ofType:nil]];
    // 如何传递参数?
    // 创建一个保存文件数据的字典
    NSDictionary *fileDict = [NSDictionary dictionaryWithObjectsAndKeys:fileData1,@"ccc.txt",fileData2,@"ooo.png",nil];

    // 创建一个保存用户名和密码的字典
    NSDictionary *params = [NSDictionary dictionaryWithObjectsAndKeys:@"jack",@"username",@"123456",@"password",nil];

    // 上传文件
    [self uploadFile:fileDict params:params fieldName:@"userfile[]"];
}



#define HMBoundary @"itheima"
- (void)uploadFile:(NSDictionary *)fileDict params:(NSDictionary *)params fieldName:(NSString *)fieldName{
    // URL
    NSURL *url = [NSURL URLWithString:@"http://localhost/post/upload-m.php"];

    // Request
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    // 设置请求方法
    request.HTTPMethod = @"POST";
    // 设置请求头:告诉服务器客户端是做文件上传
    [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",HMBoundary] forHTTPHeaderField:@"Content-Type"];
    // 设置请求体
    request.HTTPBody = [self fileData:fileDict params:params fieldName:fieldName];

    // 发送请求,上传文件
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse * _Nullable response, NSData * _Nullable data, NSError * _Nullable connectionError) {
        NSLog(@"%@--%@",response,[NSJSONSerialization JSONObjectWithData:data options:0 error:NULL]);
    }];
}

/**
 *  拼接请求体内容
 *
 *  @param fileData  要上传文件的二进制数据
 *  @param fieldName 服务器接收文件数据的使用的字段名(找服务器开发人员要)
 *  @param fileName  保存服务器使用的文件名
 */
- (NSData *)fileData:(NSDictionary *)fileDict params:(NSDictionary *)params fieldName:(NSString *)fieldName{
    NSMutableData *dataM = [NSMutableData data];
    // 遍历文件字典
    // key:保存到服务器的文件名
    [fileDict enumerateKeysAndObjectsUsingBlock:^(id  fileName, id fileData, BOOL * _Nonnull stop) {
        // 创建可变字符串用来评价请求体内容
        NSMutableString *strM = [NSMutableString stringWithFormat:@"--%@\r\n",HMBoundary];
        [strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\" \r\n",fieldName,fileName];
        [strM appendString:@"Content-Type: application/octet-stream \r\n\r\n"];

        // 将上面的字符串以UTF-8编码后拼接到dataM中(字符串类型转NSdata类型)
        [dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]];

        // 拼接文件的二进制数据
        [dataM appendData:fileData];

        // 将结尾标记字符串拼接到dataM后面
        [dataM appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
    }];

    // 遍历普通参数字典
    // key: 对应服务器接收数据的字段名
    [params enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        // 创建可变字符串用来评价请求体内容
        NSMutableString *strM = [NSMutableString stringWithFormat:@"--%@\r\n",HMBoundary];
        [strM appendFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",key];
        [strM appendFormat:@"%@\r\n",obj];

        [dataM appendData:[strM dataUsingEncoding:NSUTF8StringEncoding]];
    }];

    // 结尾标记
    NSString *tail = [NSString stringWithFormat:@"--%@--",HMBoundary];
    // 将结尾标记字符串拼接到dataM后面
    [dataM appendData:[tail dataUsingEncoding:NSUTF8StringEncoding]];

    return dataM;
}

你可能感兴趣的:(Object-C实战经验)