1. 使用 BaseURL 發(fā)送請求, 丟失地址路徑
在維護(hù)網(wǎng)絡(luò)請求的 API 時(shí), 一般都是使用 “baseURL + 相對地址” 的方式, 即:
#define baseURL @"https://www.baidu.com/"
#define login @"/login"
這樣在使用的時(shí)候, 沒什么問題, 但是, 如果你是下面這樣定義的, 可能就有問題了:
#define baseURL @"https://www.baidu.com/app/"
#define login @"/login"
會(huì)一直打印 404 的錯(cuò)誤信息, 而地址變成了 https://www.baidu.com/login
最后, 查看源碼, 發(fā)現(xiàn)問題出在, AFN 內(nèi)使用的這么一個(gè)方法使用上
+ (nullable instancetype)URLWithString:(NSString *)URLString relativeToURL:(nullable NSURL *)baseURL;
這是系統(tǒng)的一個(gè)方法, 具體原因可以查看這篇文章: ios-NSURL URLWithString:relativeToURL的坑
定義 API 的時(shí)候, 要么 baseURL 只用 host 地址, 要么就按下面的格式來定義:
- baseURL 使用 / 結(jié)尾
- 相對路徑開頭不能加 /
2. The data couldn’t be read because it isn’t in the correct format
這個(gè)問題是使用AFN發(fā)送POST請求時(shí)遇到的,奇怪的是使用GET請求能夠正常拿到數(shù)據(jù),而使用POST就不行;
控制臺輸出如下信息:
http://192.168.69.121:8080/artboss-webapp/ios/checkcode
params:{
"user_phonenumber" = 185****0925;
}
errorInfos:The data couldn’t be read because it isn’t in the correct format.
大意就是數(shù)據(jù)沒有正確的被格式化,無法讀取!后臺也接收不到我傳遞的參數(shù);
使用Charles抓包會(huì)發(fā)現(xiàn)是這樣的信息:
HTTP Status 400 - Request String parameter 'user_phonenumber' is not present
400 Bad Request!

我一看是非法的網(wǎng)絡(luò)請求,以為是我的問題,就一直在我這邊找原因,
最后才發(fā)現(xiàn),這是因?yàn)槲野l(fā)送請求時(shí)發(fā)送的字符串,和后臺需要的字符串格式不一致,發(fā)送請求時(shí),后臺需要的是text文本格式,而我發(fā)送的是json格式,導(dǎo)致后臺無法識別,接收不到數(shù)據(jù)!
后來發(fā)現(xiàn)我所用的封裝類里的請求頭,有如下設(shè)置:
[manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Accept"];
[manager.requestSerializer setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
即,默認(rèn)是使用json傳輸數(shù)據(jù)的!
把第二個(gè)注釋掉,即使用默認(rèn)的Content-Type,
并在發(fā)送請求時(shí)設(shè)置發(fā)送的字段為文本格式,即:
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
本以為會(huì)解決問題,但事實(shí)還是請求不到數(shù)據(jù)!!
最后不得已使用原生的AFNetworking進(jìn)行測試,post正常拿到了數(shù)據(jù),后來對比兩者的區(qū)別,除了上面的改動(dòng)以外,請求返回的數(shù)據(jù)也要改為文本,即:
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
這樣才正常拿到了數(shù)據(jù)!!
總之,此次網(wǎng)絡(luò)請求的異常,是由于請求和響應(yīng)的文本格式?jīng)]有統(tǒng)一,導(dǎo)致參數(shù)無法正常傳遞,數(shù)據(jù)無法正常讀取!
3. Invalid parameter not satisfying: body
在使用AFNetworking進(jìn)行傳圖操作的時(shí)候,出現(xiàn)了這個(gè)crash信息:
模擬器運(yùn)行后控制臺輸出:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: body'
*** First throw call stack:
(
0 CoreFoundation 0x0000000107ad4e65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000106c1edeb objc_exception_throw + 48
2 CoreFoundation 0x0000000107ad4cca +[NSException raise:format:arguments:] + 106
3 Foundation 0x000000010431d4de -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 198
)
libc++abi.dylib: terminating with uncaught exception of type NSException
真機(jī)的話會(huì)輸出如下信息:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: body'
*** First throw call stack:
(0x225e62eb 0x21db2dff 0x225e61c1 0x22dbcd3b 0x1b8d3f 0x1b8981 0x1909f1 0x1b4a6b 0x1a1be9 0x1906c1 0x176535 0x177171 0x193371 0x18f5cb 0x19fbb9 0x8dfcbf 0x8dfcab 0x8e4771 0x225a8fc5 0x225a74bf 0x224f9bb9 0x224f99ad 0x23773af9 0x267e5fb5 0x118b11 0x221ac873)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
而且crash的地方也不一樣:
模擬器crash到自動(dòng)釋放池

真機(jī)的話carsh到AFN的底層:

其實(shí),最主要的信息就是:Invalid parameter not satisfying: body (無效的參數(shù):body)
問題就出在body這個(gè)參數(shù)上,模擬器上看不出什么頭緒,請求參數(shù)中也沒有body這個(gè)參數(shù);但是在真機(jī)上的crash信息可以看出一些頭緒:他是crash到了這個(gè)方法里
- (void)appendPartWithHeaders:(NSDictionary *)headers
body:(NSData *)body
{
NSParameterAssert(body);
AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init];
bodyPart.stringEncoding = self.stringEncoding;
bodyPart.headers = headers;
bodyPart.boundary = self.boundary;
bodyPart.bodyContentLength = [body length];
bodyPart.body = body;
[self.bodyStream appendHTTPBodyPart:bodyPart];
}
可以看到body的類型是NSData,而設(shè)置的請求參數(shù)中,只有要發(fā)送的照片數(shù)據(jù)是NSData類型,是不是照片的問題呢?進(jìn)到AFN的底層可以發(fā)現(xiàn),AFN上傳圖片主要是用到了這個(gè)方法:
- (void)appendPartWithFileData:(NSData *)data
name:(NSString *)name
fileName:(NSString *)fileName
mimeType:(NSString *)mimeType
{
NSParameterAssert(name);
NSParameterAssert(fileName);
NSParameterAssert(mimeType);
NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary];
[mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"];
[mutableHeaders setValue:mimeType forKey:@"Content-Type"];
[self appendPartWithHeaders:mutableHeaders body:data];
}
在這個(gè)方法里調(diào)用了
[self appendPartWithHeaders:mutableHeaders body:data];
正是,程序crash的地方;
其實(shí),打斷點(diǎn)調(diào)試后也能發(fā)現(xiàn)傳入的照片數(shù)據(jù)為nil,問題的根源找到了,問題也就解決了!!!
4. terminating with uncaught exception of type NSException
雖然上面那個(gè)問題中也有這句輸出,但是這次除了這句沒有其他信息,上面的還有其他比較多的信息以供排查問題,這次是這樣的:

什么鬼都看不出來...
檢查了各種參數(shù),都沒有問題,最后不得已,斷點(diǎn)一步步執(zhí)行,最后發(fā)現(xiàn)是請求時(shí)的數(shù)據(jù)格式問題;
AFN的默認(rèn)請求的數(shù)據(jù)格式為JSON,這也是大多數(shù)后臺使用的數(shù)據(jù)格式,同樣返回格式也是JSON;
但是,但是,但是...重要的事情說三遍,總有不支持JSON的后臺接口.......
最后,我設(shè)置了一下請求頭的請求數(shù)據(jù)格式,即:
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
最后就可以正常發(fā)送請求了;
這也是因?yàn)榘l(fā)送請求時(shí)的數(shù)據(jù)格式問題,所以,一定要和后臺溝通好, 一定要和后臺溝通好, 一定要和后臺溝通好....