IOS 腾讯AI智能闲聊接口鉴权
程序员文章站
2022-05-19 08:25:41
...
首先注册账号,添加自己的应用,获取APPID和APPKEY,这两个后面获取签名的时候要用到。
你好! 这是注册地址,很简单,此处略过。https://ai.qq.com/console/home
签名算法
- 计算步骤
用于计算签名的参数在不同接口之间会有差异,但算法过程固定如下4个步骤。
一、将<key, value>请求参数对按key进行字典升序排序,得到有序的参数对列表N
二、将列表N中的参数对按URL键值对的格式拼接成字符串,得到字符串T(如:key1=value1&key2=value2),URL键值拼接过程value部分需要URL编码,URL编码算法用大写字母,例如%E8,而不是小写%e8
三、将应用**以app_key为键名,组成URL键值拼接到字符串T末尾,得到字符串S(如:key1=value1&key2=value2&app_key=**)
四、对字符串S进行MD5运算,将得到的MD5值所有字符转换成大写,得到接口请求签名 - 注意事项
一、不同接口要求的参数对不一样,计算签名使用的参数对也不一样
二、参数名区分大小写,参数值为空不参与签名
三、URL键值拼接过程value部分需要URL编码
四、签名有效期5分钟,需要请求接口时刻实时计算签名信息
五、更多注意事项,请查看常见问题
上面是官网获取sign的流程,ios实现如下:
// An highlighted block
#import "AFNetWorking.h"
#import<CommonCrypto/CommonDigest.h>
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
//
NSString *app_id = @"你的应用APPID";
NSString *APPKEY = @"你的应用APPKEY";
NSString *time_stamp = [self getNowTime];
NSString *nonce_str = [self randomStringWithLength:10];
NSMutableDictionary *params = [[NSMutableDictionary alloc]initWithDictionary: @{
@"app_id":app_id,
@"time_stamp":time_stamp,
@"nonce_str":nonce_str,
@"session":@"10000",
@"question":@"你好?"
}];
NSString *paramsAppend = [self sortedDictionary:params withAPPKEY:APPKEY];
NSString *sign = [self md5:paramsAppend];
params[@"sign"] = [sign uppercaseString];
[self post:@"https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat" andData:params andCallback:^(id JSON) {
NSLog(@"--%@", JSON);
}];
}
#pragma mark --- 请求
- (void)post:(NSString *)url
andData:(NSDictionary *)params
andCallback:(void (^)(id JSON))callback{
__block AFHTTPSessionManager * manager = [AFHTTPSessionManager manager];
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
[manager.requestSerializer setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", @"text/html", @"text/plain",nil];
[manager POST:url parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
if (callback) {
callback(responseObject);
}
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
if(error.code == -1009) {
if (callback) {
callback(nil);
}
} else if(error.code == -1001) {
//网络超时
if (callback) {
callback(nil);
}
} else {
if (callback) {
callback(nil);
}
NSLog(@"Error: %@", error);
}
}];
}
#pragma mark --- 生成随机字符串
-(NSString *)randomStringWithLength:(NSInteger)len {
NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
NSMutableString *randomString = [NSMutableString stringWithCapacity: len];
for (NSInteger i = 0; i < len; i++) {
[randomString appendFormat: @"%C", [letters characterAtIndex: arc4random_uniform([letters length])]];
}
return randomString;
}
#pragma mark --- 获取当前时间戳---10位
- (NSString *)getNowTime{
NSDate* date = [NSDate dateWithTimeIntervalSinceNow:0];
NSTimeInterval time=[date timeIntervalSince1970];
NSString *timeSp = [NSString stringWithFormat:@"%.0f", time];
return timeSp;
}
#pragma mark --- 字典的升序排列
- (NSString *)sortedDictionary:(NSDictionary *)dict withAPPKEY:(NSString *)APPKEY{
//对数组进行排序
NSArray *sortArray = [[dict allKeys] sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
return [obj1 compare:obj2 options:NSNumericSearch];
}];
//通过排列的key值获取value
NSMutableArray *valueArray = [NSMutableArray array];
for (NSString *sortsing in sortArray) {
NSString *valueString = [dict objectForKey:sortsing];
valueString = [valueString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
[valueArray addObject:valueString];
}
NSMutableArray *signArray = [NSMutableArray array];
for (int i = 0; i < sortArray.count; i++) {
NSString *keyValueStr = [NSString stringWithFormat:@"%@=%@",sortArray[i],valueArray[i]];
[signArray addObject:keyValueStr];
}
NSString *appendKey = [NSString stringWithFormat:@"%@=%@",@"app_key",APPKEY];
[signArray addObject:appendKey];
NSString *sign = [signArray componentsJoinedByString:@"&"];
return sign;
}
#pragma mark --- md5加密
- (NSString *)md5:(NSString *)input {
const char *cStr = [input UTF8String];
unsigned char digest[CC_MD5_DIGEST_LENGTH];
CC_MD5( cStr, strlen(cStr), digest );
NSMutableString *output = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
[output appendFormat:@"%02x", digest[i]];
}
return output;
}
具体用到的方法有:
1.获取当前时间戳
2.字典的升序排列
3.md5加密
4.AFNetWorking请求
遇到的问题
Q:接口返回4096是为什么?
A:参考返回码可以发现4096是服务器发现请求参数不合法或者不存在。请开发者参考具体的接口请求参数约束条件进行自检。
若所有参数均符合要求,则请开发者检查API调用方式是否正常。
对于POST方式请求,检查HTTP请求头的Content-Type是否为application/x-www-form-urlencoded
对于POST方式请求,检查HTTP请求正文数据是否符合application/x-www-form-urlencoded协议要求(注意:请求正文不是一个JSON结构,而是URL键值对字符串)
Q:接口返回16388是为什么?
A:参考返回码可以发现16388是服务器检查请求签名时,发现签名不正确。请开发者参考接口鉴权的示例代码进行检查。
Q:接口返回16389是为什么?
这是没有授权的意思哦。你需要自己把调用的接口接入到你创建的应用哦。
github代码
推荐阅读