iOS 网络请求过程参数字节数过大需要压缩

146 阅读1分钟

1. 网络请求request类:

.h 头文件:

#import <Foundation/Foundation.h>
#import <AFNetworking/AFNetworking.h>

@interface GZipRequestSerializer : AFJSONRequestSerializer

@end

.m 实现文件:

#import "GZipRequestSerializer.h"
#import "GzipTool.h"
@implementation GZipRequestSerializer
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
                               withParameters:(id)parameters
                                        error:(NSError *__autoreleasing *)error
{
    NSMutableURLRequest *mutableRequest = [super requestBySerializingRequest:request withParameters:parameters error:error].mutableCopy;
    // 追加 gzip 头
    NSAssert([mutableRequest valueForHTTPHeaderField:@"Content-Encoding"], @"gzip时 Content-Encoding 被占用");

    [mutableRequest setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"];
    
    NSData *paramsData =  [NSJSONSerialization dataWithJSONObject:parameters options:kNilOptions error:nil];
    paramsData = [GzipTool toGZipCompressData:paramsData];

    [mutableRequest setHTTPBody:paramsData];
    
    return mutableRequest;
}
@end

2. 压缩类

.h 头文件:

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface GzipTool : NSObject

/**
*  GZip压缩数据
*  @param aUnData 未压缩数据
*  @return 已压缩数据
*/
+ (NSData *)toGZipCompressData:(NSData *)aUnData;

/**
*  GZip解压数据
*  @param compressedData 压缩数据
*  @return 解压缩数据
*/
+ (NSData *)unCompressZippedData:(NSData *)compressedData;

@end

NS_ASSUME_NONNULL_END

.m 实现文件:

#import "GzipTool.h"
#import "zlib.h"

@implementation GzipTool

/*GZip压缩数据*/
+ (NSData *)toGZipCompressData:(NSData *)aUnData {
    if (![aUnData isKindOfClass:[NSData class]]) {
        return nil;
    }
    
    @try {
        if (aUnData.length == 0 || [self isGzippedData:aUnData]) {
            return aUnData;
        }
        
        z_stream stream;
        stream.zalloc = Z_NULL;
        stream.zfree = Z_NULL;
        stream.opaque = Z_NULL;
        stream.avail_in = (uint) aUnData.length;
        stream.next_in = (Bytef *) (void *) aUnData.bytes;
        stream.total_out = 0;
        stream.avail_out = 0;
        
        static const NSUInteger ChunkSize = 16384;
        
        NSMutableData *output = nil;
        if (deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY) == Z_OK) {
            output = [NSMutableData dataWithLength:ChunkSize];
            while (stream.avail_out == 0) {
                if (stream.total_out >= output.length) {
                    output.length += ChunkSize;
                }
                stream.next_out = (uint8_t *) output.mutableBytes + stream.total_out;
                stream.avail_out = (uInt)(output.length - stream.total_out);
                deflate(&stream, Z_FINISH);
            }
            deflateEnd(&stream);
            output.length = stream.total_out;
        }
        
        return output;
    }
    @catch (NSException *exception) {
        NSLog(@"gzip error: %@", exception);
        return nil;
    }
}

+ (NSData *)unCompressZippedData:(NSData *)compressedData
{
    if ([compressedData length] == 0) return compressedData;
    
    unsigned long full_length = compressedData.length;
    
    unsigned long half_length = [compressedData length] / 2;
    NSMutableData *decompressed = [NSMutableData dataWithLength: full_length + half_length];
    BOOL done = NO;
    int status;
    z_stream strm;
    strm.next_in = (Bytef *)[compressedData bytes];
    strm.avail_in = (uint) [compressedData length];
    strm.total_out = 0;
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    if (inflateInit2(&strm, (15+32)) != Z_OK) return nil;
    while (!done) {
        // Make sure we have enough room and reset the lengths.
        if (strm.total_out >= [decompressed length]) {
            [decompressed increaseLengthBy: half_length];
        }
        // chadeltu 加了(Bytef *)
        strm.next_out = (Bytef *)[decompressed mutableBytes] + strm.total_out;
        strm.avail_out = (uint)(decompressed.length - strm.total_out);
        // Inflate another chunk.
        status = inflate (&strm, Z_SYNC_FLUSH);
        if (status == Z_STREAM_END) {
            done = YES;
        } else if (status != Z_OK) {
            break;
        }
        
    }
    if (inflateEnd (&strm) != Z_OK) return nil;
    // Set real length.
    if (done) {
        [decompressed setLength: strm.total_out];
        return [NSData dataWithData: decompressed];
    } else {
        return nil;
    }
}

+ (BOOL)isGzippedData:(NSData *)aData {
    const UInt8 *bytes = (const UInt8 *) aData.bytes;
    return (aData.length >= 2 && bytes[0] == 0x1f && bytes[1] == 0x8b);
}


@end