原文:https://blog.csdn.net/yunqiinsight/article/details/80134267
https://github.com/ChenYilong/CYLCURLNetworking?spm=a2c4e.11153959.blogcont543412.13.1bda7efeTdgxCQ
NSURLProtocol 攔截 NSURLSession 請(qǐng)求時(shí)body丟失問(wèn)題解決方案探討
在支持POST請(qǐng)求過(guò)程中會(huì)遇到丟失 body的 問(wèn)題秕狰,有以下幾種解決方法:
換用 NSURLConnection趾痘。NSURLConnection 與 NSURLSession
相比會(huì)遇到較多的性能問(wèn)題撮弧,同時(shí)Apple的一些新特性也無(wú)法使用页衙,終究會(huì)被淘汰狮杨,不作考慮排龄。
body放header的方法腕唧,2M以下沒(méi)問(wèn)題,超過(guò)2M會(huì)導(dǎo)致請(qǐng)求延遲赔退,超過(guò) 10M 就直接 Request timeout熏矿。而且無(wú)法解決
Body 為二進(jìn)制數(shù)據(jù)的問(wèn)題,因?yàn)镠eader里都是文本數(shù)據(jù)离钝。
換用 Get 請(qǐng)求,不使用 Post 請(qǐng)求褪储。這個(gè)也是可行的卵渴,但是畢竟對(duì)請(qǐng)求方式有限制,終究還是要解決 Post
請(qǐng)求所存在的問(wèn)題鲤竹。如果是基于舊項(xiàng)目做修改浪读,則侵入性太大昔榴。這種方案適合新的項(xiàng)目。
另一種方法是我們下面主要要講的碘橘,使用 HTTPBodyStream 獲取 body互订,并賦值到 body
中,具體的代碼如下痘拆,可以解決上面提到的問(wèn)題:
//
//? NSURLRequest+CYLNSURLProtocolExtension.h
//
//
//? Created by ElonChan on 28/07/2017.
//? Copyright ? 2017 ChenYilong. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSURLRequest (CYLNSURLProtocolExtension)
- (NSURLRequest *)cyl_getPostRequestIncludeBody;
@end
//
//? NSURLRequest+CYLNSURLProtocolExtension.h
//
//
//? Created by ElonChan on 28/07/2017.
//? Copyright ? 2017 ChenYilong. All rights reserved.
//
#import "NSURLRequest+CYLNSURLProtocolExtension.h"
@implementation NSURLRequest (CYLNSURLProtocolExtension)
- (NSURLRequest *)cyl_getPostRequestIncludeBody {
? ? return [[self cyl_getMutablePostRequestIncludeBody] copy];
}
- (NSMutableURLRequest *)cyl_getMutablePostRequestIncludeBody {
? ? NSMutableURLRequest * req = [self mutableCopy];
? ? if ([self.HTTPMethod isEqualToString:@"POST"]) {
? ? ? ? if (!self.HTTPBody) {
? ? ? ? ? ? NSInteger maxLength = 1024;
? ? ? ? ? ? uint8_t d[maxLength];
? ? ? ? ? ? NSInputStream *stream = self.HTTPBodyStream;
? ? ? ? ? ? NSMutableData *data = [[NSMutableData alloc] init];
? ? ? ? ? ? [stream open];
? ? ? ? ? ? BOOL endOfStreamReached = NO;
? ? ? ? ? ? //不能用 [stream hasBytesAvailable]) 判斷仰禽,處理圖片文件的時(shí)候這里的[stream hasBytesAvailable]會(huì)始終返回YES,導(dǎo)致在while里面死循環(huán)纺蛆。
? ? ? ? ? ? while (!endOfStreamReached) {
? ? ? ? ? ? ? ? NSInteger bytesRead = [stream read:d maxLength:maxLength];
? ? ? ? ? ? ? ? if (bytesRead == 0) { //文件讀取到最后
? ? ? ? ? ? ? ? ? ? endOfStreamReached = YES;
? ? ? ? ? ? ? ? } else if (bytesRead == -1) { //文件讀取錯(cuò)誤
? ? ? ? ? ? ? ? ? ? endOfStreamReached = YES;
? ? ? ? ? ? ? ? } else if (stream.streamError == nil) {
? ? ? ? ? ? ? ? ? ? [data appendBytes:(void *)d length:bytesRead];
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? req.HTTPBody = [data copy];
? ? ? ? ? ? [stream close];
? ? ? ? }
? ? }
? ? return req;
}
@end
在用于攔截請(qǐng)求的 NSURLProtocol 的子類(lèi)中實(shí)現(xiàn)方法 +canonicalRequestForRequest: 并處理 request 對(duì)象:
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
? return [request cyl_getPostRequestIncludeBody];
}
+[NSURLProtocol canInitWithRequest:] 負(fù)責(zé)篩選哪些網(wǎng)絡(luò)請(qǐng)求需要被攔截
+[NSURLProtocol canonicalRequestForRequest:] 負(fù)責(zé)對(duì)需要攔截的網(wǎng)絡(luò)請(qǐng)求NSURLRequest 進(jìn)行重新構(gòu)造吐葵。
這里有一個(gè)注意點(diǎn):+[NSURLProtocol canonicalRequestForRequest:] 的執(zhí)行條件是 +[NSURLProtocol canInitWithRequest:] 返回值為 YES。
注意在攔截 NSURLSession 請(qǐng)求時(shí)桥氏,需要將用于攔截請(qǐng)求的 NSURLProtocol 的子類(lèi)添加到 NSURLSessionConfiguration 中温峭,用法如下:
? NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
? ? NSArray *protocolArray = @[ [CYLURLProtocol class] ];
? ? configuration.protocolClasses = protocolArray;
? ? NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
更新:處理之后還是無(wú)效,把post換成get字支。凤藏。