IOS中json字符串原生数据请求&IOS跨平台AES128字符串加解密&AFNetworking框架的简单封装使用

@废话在前


IOS开发中原始的数据请求是以字符串的形式,字符串参数传到服务器,然后接收服务器返回的字符串进行解析。


通常一个完整的数据请求过程中数据处理经如下几个阶段:

1.制作参数,用NSDictionary封装,即一个son对象;


2.json对象转成json字符串;


3.字符串加密成密文(可选);


4.将json字符串(或加密后的密文)作为参数发送请求;


5.接受服务器返回的数据NSData,并转成字符串;


6.字符串解密(可选);


7.json字符串转json对象(NSDictionary);



一.IOS原生数据请求与数据解析


这里建立一个IOS原生session回话任务封装一个post请求(post请求更安全常用):

//
//  RequestSingleton.h
//  JXHDemo
//
//  Created by Xinhou Jiang on 6/12/16.
//  Copyright © 2016 Jiangxh. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface RequestSingleton : NSObject

/**
 *  获取QueuesSingleton单例对象
 */
+ (RequestSingleton *)Ins;

/**
 * 原生POST请求(最基础的请求参数是字符串,这里原生的请求参数是一个json字符串)
 */
- (void) POST: (NSString *)url param: (NSString *)param success:(void(^)(id json))success failure: (void(^)(NSError *error))flaiure;

@end

//
//  RequestSingleton.m
//  JXHDemo
//
//  Created by Xinhou Jiang on 6/12/16.
//  Copyright © 2016 Jiangxh. All rights reserved.
//

#import "RequestSingleton.h"

@interface RequestSingleton()

/**
 * session,创建一个共用的即可
 */
@property(nonatomic, strong)NSURLSession *session;

@end

@implementation RequestSingleton

/**
 *  获取单例对象
 */
+ (RequestSingleton *)Ins
{
    static dispatch_once_t once;
    static id sharedInstance;
    dispatch_once(&once, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

/**
 *  init
 */
- (id)init
{
    if (self = [super init])
    {
        // 通用session
        _session = [NSURLSession sharedSession];
    }
    return self;
}

/**
 * 原生POST请求, 客可对此进一步封装,进行参数的拼接,加密等等
 */
- (void)POST:(NSString *)url param:(NSString *)param success:(void (^)(id json))success failure:(void (^)(NSError *))flaiure {
    // url对象
    NSURL *URL = [NSURL URLWithString:url];
    // request
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
    // post请求
    request.HTTPMethod = @"POST";
    // 参数
    request.HTTPBody = [param dataUsingEncoding:NSUTF8StringEncoding];
    // 请求超时
    request.timeoutInterval = 30;
    
    //根据会话对象创建一个发送请求Task
    NSURLSessionDataTask *dataTask = [_session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        
        // 解析数据, 将NSData转成json对象
        id json = [self decrypeJsonWithData:data];
        
        // 如果error为nil说明没有网络错误,请求成功
        if (!error) {
            // 将数据上抛传出去
            success(json);
            // 打印
            NSLog(@"返回数据:%@",json);
        }else {
            // 网络错误,请求失败,包括请求超时等等
            flaiure(error);
        }
    }];
    
    //执行任务
    [dataTask resume];
}

/**
 *  NSData转JSON对象
 */
- (id)decrypeJsonWithData:(NSData *)data
{
    // 1. 转成字符串
    NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    // 2. 解密
    // 如果是加密传输在这里进行解密
    
    // 3. 转成json对象
    return [NSJSONSerialization JSONObjectWithData:[jsonStr dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:nil];
}

@end

使用方法是将上面的类加入工程,然后调用单例类的类函数即可:

#import "RequestSingleton.h"
/**
 * 原生网络请求测试示例
 */
- (void)request {
    // 1.服务器url接口
    NSString *url = @"";
    // 2.制作参数
    NSMutableDictionary *paramDic = [[NSMutableDictionary alloc]init];
    [paramDic setObject:@"919575700@qq.com" forKey:@"username"];
    [paramDic setObject:@"jxh123" forKey:@"password"];
    // 转成json字符串,用到MJExtension归档插件
    NSString *param = [paramDic JSONString];
    // post请求
    [[RequestSingleton Ins] POST:url param:param success:^(id json) {
        // 请求成功
    } failure:^(NSError *error) {
        // 请求错误
    }];
}




二.AES128加解密(解决ios与服务器等其他平台加密密文尾巴不一致的问题)


加密解密的函数封装在下面的工具类中(其中用到了谷歌的GTMBase64编码工具类可网上自行下载):

#import <Foundation/Foundation.h>

@interface DES3Util : NSObject

// 加密
+ (NSString*) AES128Encrypt:(NSString *)plainText;
// 解密
+ (NSString*) AES128Decrypt:(NSString *)encryptText;

@end
#import "DES3Util.h"
#import <CommonCrypto/CommonCryptor.h>
#import "GTMBase64.h"

@implementation DES3Util

// 加密
+(NSString *)AES128Encrypt:(NSString *)plainText
{
    char keyPtr[kCCKeySizeAES128+1];
    memset(keyPtr, 0, sizeof(keyPtr));
    [AES128Key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    
    char ivPtr[kCCBlockSizeAES128+1];
    memset(ivPtr, 0, sizeof(ivPtr));
    [AES128Iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
    
    NSData* data = [plainText dataUsingEncoding:NSUTF8StringEncoding];
    NSUInteger dataLength = [data length];
    
    int diff = kCCKeySizeAES128 - (dataLength % kCCKeySizeAES128);
    int newSize = 0;
    
    if(diff > 0)
    {
        newSize = (int)dataLength + diff;
    }
    
    char dataPtr[newSize];
    memcpy(dataPtr, [data bytes], [data length]);
    for(int i = 0; i < diff; i++)
    {
        dataPtr[i + dataLength] = 0x00;
    }
    
    size_t bufferSize = newSize + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    memset(buffer, 0, bufferSize);
    
    size_t numBytesCrypted = 0;
    
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          kCCAlgorithmAES128,
                                          0x0000,               //No padding
                                          keyPtr,
                                          kCCKeySizeAES128,
                                          ivPtr,
                                          dataPtr,
                                          sizeof(dataPtr),
                                          buffer,
                                          bufferSize,
                                          &numBytesCrypted);
    
    if (cryptStatus == kCCSuccess) {
        NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
        
        return [GTMBase64 stringByEncodingData:resultData];
    }
    free(buffer);
    return nil;
}

// 解密
+(NSString *)AES128Decrypt:(NSString *)encryptText
{
    char keyPtr[kCCKeySizeAES128 + 1];
    memset(keyPtr, 0, sizeof(keyPtr));
    [AES128Key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    
    char ivPtr[kCCBlockSizeAES128 + 1];
    memset(ivPtr, 0, sizeof(ivPtr));
    [AES128Iv getCString:ivPtr maxLength:sizeof(ivPtr) encoding:NSUTF8StringEncoding];
    
    NSData *data = [GTMBase64 decodeData:[encryptText dataUsingEncoding:NSUTF8StringEncoding]];
    NSUInteger dataLength = [data length];
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);
    
    size_t numBytesCrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
                                          kCCAlgorithmAES128,
                                          0x0000,
                                          keyPtr,
                                          kCCBlockSizeAES128,
                                          ivPtr,
                                          [data bytes],
                                          dataLength,
                                          buffer,
                                          bufferSize,
                                          &numBytesCrypted);
    if (cryptStatus == kCCSuccess) {
        NSData *resultData = [NSData dataWithBytesNoCopy:buffer length:numBytesCrypted];
        return [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
    }
    free(buffer);
    return nil;
}

@end
实际应用中会发现上面的加解密方法在ios本地没有问题,但和服务器加密的密文尾巴不一致,导致服务器无法解析,需要对密文进行特殊字符的处理,在发送请求前将加密的参数密文经过下面的函数处理一下即可:

/**
 *  aes128加密后的密文编码处理,参数为128加密后的密文
 */
- (NSString *)AES128Convert: (NSString *)aes128 {
    
    NSString *charactersToEscape = @"!*'();:@&=+$,/?%#[]\" ";
    NSCharacterSet *allowedCharacters = [[NSCharacterSet characterSetWithCharactersInString:charactersToEscape] invertedSet];
    
    return [aes128 stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
}




三.AFNetworking网络请求框架的使用


AFNetworking框架基础介绍:http://blog.csdn.net/cordova/article/details/51614695


未完待续... ...

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr_厚厚

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值