iOS x-www-form-urlencoded 格式 Post 下载文件

1,742 阅读2分钟

公司项目有集成百度合成语音 API 需求,而 API 在下载 mp3 文件的时候需要使用 x-www-form-urlencoded 格式请求文件下载,但谷歌找的代码都不符合需求,所以有了这篇文章。

由于 AFNetworking3.0 及以上封装的最外层 AFHTTPSessionManager 的 POST 方法不能完成 application/x-www-form-urlencoded 的请求, 所以必须自己作出一些定制。

首先,正常的 AFNetworking Post 方法已经不适用了,要自己初始化一个符合要求的 Request 。

    // 初始化Request
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:15.0];
    // http method
    [request setHTTPMethod:@"POST"];
    // http header
    // 这一步设置请求格式,是重点
    [request addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];

然后设置 HTTPBody,

    // http body
    NSMutableString *paraString = [NSMutableString string];
    for (NSString *key in [params allKeys]) {
        [paraString appendFormat:@"&%@=%@", key, params[key]];
    }
    [paraString deleteCharactersInRange:NSMakeRange(0, 1)]; // 删除多余的&号
    [request setHTTPBody:[paraString dataUsingEncoding:NSUTF8StringEncoding]];

最后构建一个 AFManager 并发送请求下载文件。
整个完整代码如下:

+ (void)downloadMp3FileWithText:(NSString *)text token:(NSString *)token progres:(void(^)(CGFloat percent))progress completion:(void (^)(NSURL * mp3FilePath))completion{
    // 初始化URL
    NSURL *URL = [NSURL URLWithString:@"https://tsn.baidu.com/text2audio"];
    // 初始化参数
    NSDictionary * params = @{
        @"tex":text,
        @"tok":token,
        @"cuid":@"4234234",
        @"ctp":@"1",
        @"lan":@"zh",
    };
    
    // 初始化Request
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:15.0];
    // http method
    [request setHTTPMethod:@"POST"];
    // http header
    // 这一步是重点
    [request addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
    
    // http body
    NSMutableString *paraString = [NSMutableString string];
    for (NSString *key in [params allKeys]) {
        [paraString appendFormat:@"&%@=%@", key, params[key]];
    }
    [paraString deleteCharactersInRange:NSMakeRange(0, 1)]; // 删除多余的&号
    [request setHTTPBody:[paraString dataUsingEncoding:NSUTF8StringEncoding]];
    
    // 初始化AFManager
    AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration: [NSURLSessionConfiguration defaultSessionConfiguration]];
    AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer];
    serializer.acceptableContentTypes = [NSSet setWithObjects:
                                         @"text/plain",
                                         @"application/json",
                                         @"text/html", nil];
    manager.responseSerializer = serializer;
    
     //下载Task操作
    NSURLSessionDownloadTask *_downloadTask = [manager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {
        //进度
        if(progress){
            progress(downloadProgress.fractionCompleted);
        }
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        
        NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
        NSString *path = [cachesPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%u%@",arc4random_uniform(100000),response.suggestedFilename]];
        return [NSURL fileURLWithPath:path];
        
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        // filePath就是你下载文件的位置,你可以解压,也可以直接拿来使用
        if (error) {
            if(completion){
                completion(nil);
            }
        } else {
            if(completion){
                completion(filePath);
            }
        }
    }];
    [_downloadTask resume];
}

上面的代码也涉及到了如何下载一个文件,希望能帮助到大家。