AFNetworking post form 表單提交

參考文章 iOS 使用AFNetworking的form表單請(qǐng)求

AFNetworking post請(qǐng)求方式有application/x-www-form-urlencoded、multipart/form-data、application/json。其中application/json就是我們常見(jiàn)的post請(qǐng)求,使用AFN直接請(qǐng)求即可。
form表單請(qǐng)求,是一種特殊的post請(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/jpgimage/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-databoundary。這里最坑的就是設(shè)置了multipart/form-databoundary,還能請(qǐng)求成功,讓人一度人為自己寫(xiě)的代碼沒(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ǔ)全這一部分

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容