首先說(shuō)明下form
表單請(qǐng)求颤专,是一種特殊的post
請(qǐng)求纽哥,請(qǐng)求方式有application/x-www-form-urlencoded
、multipart/form-data
栖秕、application/json
春塌。其中application/json
就是我們常見(jiàn)的post請(qǐng)求,使用AFN直接請(qǐng)求即可簇捍。
下面開(kāi)始正式的內(nèi)容只壳,如何使用AFNetworking
完成form表單請(qǐng)求
1、application/x-www-form-urlencoded
直接上代碼:
+ (AFHTTPSessionManager *)getManagerWithReqType:(requestType)reqType{
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
if(reqType == REQ_Form){
[manager.requestSerializer setValue:@"application/x-www-form-urlencoded;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
}else{
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
[manager.requestSerializer setValue:@"application/json;text/html;charset=utf-8" forHTTPHeaderField:@"Content-Type"];
}
return manager;
}
這種form表單請(qǐng)求方式和我們常見(jiàn)的post請(qǐng)求方式垦写,只有這一個(gè)地方需要區(qū)別吕世,特別注意以下兩句不能出現(xiàn)在application/x-www-form-urlencoded
請(qǐng)求方式中
manager.requestSerializer = [AFJSONRequestSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
剩下的部分和常見(jiàn)的post請(qǐng)求一致彰触,請(qǐng)求時(shí)只需要調(diào)用:
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
2梯投、multipart/form-data
目前個(gè)人在項(xiàng)目中遇到的情況,主要用于上傳二進(jìn)制文件,使用時(shí)只需要在常見(jiàn)post請(qǐng)求的基礎(chǔ)上分蓖,設(shè)置Content-Type
為:
[manager.requestSerializer setValue:@"multipart/form-data; boundary=----WebKitFormBoundaryHzyefUottpz7ltKf"forHTTPHeaderField:@"Content-Type"];
在調(diào)用方法上稍有不同尔艇,multipart/form-data
調(diào)用AFN的constructingBodyWithBlock方法:
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
headers:(nullable NSDictionary <NSString *, NSString *> *)headers
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
以上傳視頻為例:
+(void)uploadVideoUseAFN:(NSURL *)filePath andUrl:(NSString *)urlString{
AFHTTPSessionManager *manager = [self getManager];
/// 要上傳的二進(jìn)制文件
NSData *videoData = [NSData dataWithContentsOfURL:filePath];
/// 二進(jìn)制文件在服務(wù)器保存的路勁
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
formatter.dateFormat =@"yyyyMMddHHmmss";
NSString *str = [formatter stringFromDate:[NSDate date]];
NSString *fileName = [NSString stringWithFormat:@"%@.mp4", str];
NSURLSessionDataTask *task = [manager POST:urlString parameters:nil headers:nil constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
/// 拼接formdata
[formData appendPartWithFileData:videoData
name:@"myFile"
fileName:fileName
mimeType:@"video/mpeg"];
} progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
[task resume];
}
疑點(diǎn)1、關(guān)于mimeType的設(shè)置
使用AFNetworking
不需要設(shè)置額外的參數(shù)(如Content-Disposition
)么鹤,因?yàn)樵?code>AFNetworking完成form提交時(shí)终娃,下面的方法會(huì)自動(dòng)設(shè)置Content-Disposition
為@"form-data; name=\"%@\"; filename=\"%@\"
- (void)appendPartWithFileData:(NSData *)data
name:(NSString *)name
fileName:(NSString *)fileName
mimeType:(NSString *)mimeType;
覺(jué)得不妥的也可以查看appendPartWithFileData
的具體實(shí)現(xiàn),會(huì)發(fā)現(xiàn)如下內(nèi)容:
[mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"];
[mutableHeaders setValue:mimeType forKey:@"Content-Type"];
這里有一個(gè)痛點(diǎn)蒸甜,就是關(guān)于mimeType
的設(shè)置棠耕,圖片和視頻都很方便,可以直接設(shè)置為image/jpg
柠新、image/png
窍荧、video/mpeg
等(最好和后臺(tái)對(duì)一下,因?yàn)橛行╅_(kāi)發(fā)會(huì)指定文件類型恨憎,設(shè)置不一致會(huì)請(qǐng)求失敗
)蕊退。
但對(duì)于文件上傳,mimeType
設(shè)置什么就比較懵憔恳,這里可以設(shè)置萬(wàn)能類型application/octet-stream
瓤荔,服務(wù)器會(huì)自動(dòng)解析文件類型。關(guān)于如何獲取文件的mimeType
钥组,可以查看
疑點(diǎn)2输硝、關(guān)于使用AFNetworking提交Form表單,請(qǐng)求成功了程梦,但是后臺(tái)接收到的數(shù)據(jù)為空
正常情況下我們使用form提交腔丧,都會(huì)在header中設(shè)置:
[manager.requestSerializer setValue:@"multipart/form-data; boundary=----WebKitFormBoundaryHzyefUottpz7ltKf"forHTTPHeaderField:@"Content-Type"];
后臺(tái)沒(méi)有接收到傳過(guò)去的數(shù)據(jù)就是因?yàn)樵O(shè)置了multipart/form-data
和boundary
。這里最坑的就是設(shè)置了multipart/form-data
和boundary
作烟,還能請(qǐng)求成功愉粤,讓人一度人為自己寫的代碼沒(méi)有半點(diǎn)毛病。
解決辦法:
+ (void)uploadImageWIthimageData:(NSData *)imageData{
NSString *requestUrl = @"";
/// 設(shè)置filename
NSDateFormatter *formatter = [[NSDateFormatter alloc]init];
formatter.dateFormat =@"yyyyMMddHHmmss";
NSString *str = [formatter stringFromDate:[NSDate date]];
NSString *fileName = [NSString stringWithFormat:@"%@.jpg", str];
/// 請(qǐng)求配置
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
/// 注意:如果返回結(jié)果是json類型按如下設(shè)置拿撩,data類型manager.responseSerializer = [AFHTTPResponseSerializer serializer];
manager.responseSerializer = [AFJSONResponseSerializer serializer];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json",@"text/html",@"image/jpeg",@"image/png",@"application/octet-stream",@"text/json",nil];
/// 設(shè)置上傳參數(shù)衣厘,經(jīng)過(guò)測(cè)試這個(gè)可以不用傳
NSDictionary *params = @{@"file":imageData};
/// 設(shè)置header
NSDictionary *headers = @{@"Authorization":@""};
NSURLSessionDataTask *task = [manager POST:requestUrl parameters:params headers:headers constructingBodyWithBlock:^(id<AFMultipartFormData> _Nonnull formData) {
[formData appendPartWithFileData:imageData
name:@"file"
fileName:fileName
mimeType:@"image/jpg"];
} progress:^(NSProgress * _Nonnull uploadProgress) {
} success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
}];
[task resume];
}
你也不要覺(jué)得這樣就不是一個(gè)multipart/form-data
類型的請(qǐng)求了,因?yàn)?code>AFNetworking會(huì)自動(dòng)補(bǔ)全這一部分