AFNetworking是iOS开发中非常常见的网络请求框架.基于多次的迭代非常稳定.但是使用不当可能就会有一些小问题
简概:
每次请求均更新AFHTTPRequestSerializer中的sign参数.导致并发时.签名出错.请求失败的问题
细节描述:
项目需要将请求参数进行多次加密获取签名.并且放入到请求头中.就需要在每次请求时都要更新requestSerializer的值.
我们继承AFHTTPSessionManager的JTNetServers是一个单例.里面的参数requestSerializer也是唯一的.
每次请求获取mutableRequest时.即会重新获取HTTPRequestHeaders对象.需要用到requestSerializer中的参数.而该对象取决于self.mutableHTTPRequestHeaders.而从0处可以看出self.mutableHTTPRequestHeaders是会随着外界的设置改变而改变.并发时低概率的情况就会导致:下一个请求设置更改了头文件中的值.会更改上一个请求的httpHeaderField对象.这样就会让上一个请求的sign和请求的参数不匹配而请求失败
//0
- (void)setValue:(NSString *)value
forHTTPHeaderField:(NSString *)field
{
dispatch_barrier_async(self.requestHeaderModificationQueue, ^{
[self.mutableHTTPRequestHeaders setValue:value forKey:field];
});
}
//1
- (NSDictionary *)HTTPRequestHeaders {
NSDictionary __block *value;
dispatch_sync(self.requestHeaderModificationQueue, ^{
value = [NSDictionary dictionaryWithDictionary:self.mutableHTTPRequestHeaders];
});
return value;
}
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(request);
NSMutableURLRequest *mutableRequest = [request mutableCopy];
//2
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];
.......
return mutableRequest;
}
改进:
给AFURLRequestSerialization添加一个缓存池.将每次请求添加进去.响应的key是以urlString和参数parameters拼接达到唯一性.value则是需要上传时的headerDict.相关代码如下
AFURLRequestSerialization.h相关代码
/**
请求header缓存池.
*/
@property (nonatomic, strong) NSMutableDictionary<NSString *,NSDictionary *> * httpRequesHeaderMuDict ;
/**
将请求头添加到缓存池中
@param key 请求url+parameters参数拼接的字符串
*/
-(void)reloadCustomHttpRequestHeadersWithKey:(NSString *)key;
/**
将请求头从缓存池中删除
@param key 请求url+parameters参数拼接的字符串
*/
-(void)deleteCustomHttpRequestHeadersWithKey:(NSString *)key;
AFURLRequestSerialization.m相关代码
-(NSMutableDictionary<NSString *,NSDictionary *> *)httpRequesHeaderMuDict
{
if (!_httpRequesHeaderMuDict) {
_httpRequesHeaderMuDict = [NSMutableDictionary dictionary];
}
return _httpRequesHeaderMuDict;
}
-(void)reloadCustomHttpRequestHeadersWithKey:(NSString *)key{
dispatch_sync(self.requestHeaderModificationQueue, ^{
NSDictionary * customHttpRequestHeaders = [NSDictionary dictionaryWithDictionary:self.mutableHTTPRequestHeaders];
[self.httpRequesHeaderMuDict setValue:customHttpRequestHeaders forKey:key];
NSLog(@"----------------------->%@__%zd",self.httpRequesHeaderMuDict.allKeys,self.httpRequesHeaderMuDict.allKeys.count);
});
}
-(void)deleteCustomHttpRequestHeadersWithKey:(NSString *)key{
dispatch_sync(self.requestHeaderModificationQueue, ^{
[self.httpRequesHeaderMuDict removeObjectForKey:key];
NSLog(@"----------------------->删除->%@__%zd",self.httpRequesHeaderMuDict.allKeys,self.httpRequesHeaderMuDict.allKeys.count);
});
}
//将2处的代码更改为4.即从缓存池中.根据唯一的key.取出唯一的requestHeader字典数据做请求
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(request);
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
return [super requestBySerializingRequest:request withParameters:parameters error:error];
}
NSMutableURLRequest *mutableRequest = [request mutableCopy];
//4
NSString * httpRequesKey = [NSString stringWithFormat:@"%@_%@",request.URL,parameters ? parameters : @""];
NSDictionary * httpRequestHeaders = self.httpRequesHeaderMuDict[httpRequesKey];
[httpRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];
..........
return mutableRequest;
}
最后在请求前添加到缓存池.请求后移除缓存池即可
NSString * httpRequesKey = [NSString stringWithFormat:@"%@_%@",URLString,parameters ? parameters : @""];
[self.requestSerializer reloadCustomHttpRequestHeadersWithKey:httpRequesKey];
__weak typeof(self)weakSelf = self;
[self POST:URLString parameters:parameters progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
[self.requestSerializer deleteCustomHttpRequestHeadersWithKey:httpRequesKey];
转载于:https://www.jianshu.com/p/0659c4c9d5a4