Closed Vincentzzg closed 5 years ago
这么快merge了😄
我又仔细看了代码,最新版本仓库代码由于默认的sessionManager的创建,没有指定responseSerializer
- (AFHTTPSessionManager *)sessionManagerWithService:(id<CTServiceProtocol>)service
{
AFHTTPSessionManager *sessionManager = nil;
if ([service respondsToSelector:@selector(sessionManager)]) {
sessionManager = service.sessionManager;
}
if (sessionManager == nil) {
sessionManager = [AFHTTPSessionManager manager];
}
return sessionManager;
}
而AFHTTPSessionManager实现中 self.responseSerializer = [AFJSONResponseSerializer serializer];默认是AFJSONResponseSerializer
- (instancetype)initWithBaseURL:(NSURL *)url
sessionConfiguration:(NSURLSessionConfiguration *)configuration
{
self = [super initWithSessionConfiguration:configuration];
if (!self) {
return nil;
}
// Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
url = [url URLByAppendingPathComponent:@""];
}
self.baseURL = url;
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];//默认AFJSONResponseSerializer
return self;
}
而AFJSONResponseSerializer中对responseObjectForResponse方法的实现中已经对数据进行了转换,
#pragma mark - AFURLResponseSerialization
- (id)responseObjectForResponse:(NSURLResponse *)response
data:(NSData *)data
error:(NSError *__autoreleasing *)error
{
if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) {
if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) {
return nil;
}
}
// Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization.
// See https://github.com/rails/rails/issues/1742
BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
if (data.length == 0 || isSpace) {
return nil;
}
NSError *serializationError = nil;
id responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];//这里已经对json数据进行了序列化,转成了对象
...
}
所以理论上DemoService里面的resultWithResponseData方法里面responseData会一直是NSDdictionary
我觉得这里应该是两种都会有的,因为有时候后台返回的是json的有时候后台返回的是data类型 在CTApiProxy.m中,调AFNetworking请求的回调中responseData直接是用nsdata接收的,我觉得这里需要修改不知道我理解的对不对
我说下我的理解,其实后台返回的数据,客户端的网络框架拿到的报文都是NSData类型的数据,你说的“有时候后台返回的是json的有时候后台返回的是data类型”,是AFNetwork根据设置的responseSerializer做了数据转换,不同的响应序列化器会返回不同类型的数据,你可以自己测试下,往底层去跟。
可以看下AFURLSessionManager里面的代码中的实现
#pragma mark - NSURLSessionTaskDelegate
- (void)URLSession:(__unused NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
{
...
其实这边我的设计思路是让service来处理返回数据的。
service对象不光负责提供request,也负责解析该service的API的response。
在上面的service protocol中大家就能看到我的设计了。虽然demo这边怎么改都无所谓,但实际上还是要看service的设计初衷的。
如果按照这个设计初衷来,proxy就无所谓response是什么类型的数据了,因为最终都是交给service去处理的。
嗯嗯,能体会到田大哥的设计初衷,我是从最开始的RTNetworking框架开始用的,一直跟到现在的
昨天我确实没有考虑到这一层,考虑到这一层的话,修改的方向就不一样了,协议中的返回类型也要配合改掉,因为不确定返回值的类型,所以应该保持AFHTTPSessionManager的返回类型id _Nullable responseObject。
现在的返回类型NSData、还有下面几个key值的定义,都是默认proxy返回数据是JSON数据、NSData类型,对于使用者来说有很大的迷惑性
NSString * const kCTApiProxyValidateResultKeyResponseJSONObject = @"kCTApiProxyValidateResultKeyResponseJSONObject";
NSString * const kCTApiProxyValidateResultKeyResponseJSONString = @"kCTApiProxyValidateResultKeyResponseJSONString";
NSString * const kCTApiProxyValidateResultKeyResponseData = @"kCTApiProxyValidateResultKeyResponseData";
CTLogger类的方法名和参数也要微调下
+ (NSString *)logDebugInfoWithResponse:(NSHTTPURLResponse *)response rawResponseData:(NSData *)rawResponseData responseString:(NSString *)responseString request:(NSURLRequest *)request error:(NSError *)error
等下我提交个新的PR给你看下
嗯,之前的写法确实对使用者产生了迷惑~CTNetworking改造的时候我这一点也忽略了😂
直接下载仓库代码,运行点击send request,崩溃。 方法
我加了一些类型判断和容错的代码