AFNetWorking源碼之AFHTTPSessionManager

1 概述

AFHTTPSessionManagerAFURLSessionManager的子類丢氢。我們可以通過(guò)這個(gè)類做HTTP請(qǐng)求聊记。其實(shí)整個(gè)AFHTTPSessionManager邏輯很簡(jiǎn)單,只是用HTTP的方式拼接了請(qǐng)求召娜,并且調(diào)用父類的方式做處理运褪。我會(huì)通過(guò)AFHTTPSessionManagerapi來(lái)講一下POST上傳數(shù)據(jù)的幾種基本格式,然后我再隨便分析一下AFHTTPSessionManager

2 POST請(qǐng)求的常用格式

HTTP/1.1協(xié)議規(guī)定的HTTP請(qǐng)求方法有OPTIONS玖瘸、GET秸讹、HEAD、POST雅倒、PUT璃诀、DELETE、TRACE蔑匣、CONNECT 這幾種劣欢。其中POST一般用來(lái)向服務(wù)端提交數(shù)據(jù),接下來(lái)要討論P(yáng)OST提交數(shù)據(jù)的幾種方式裁良。協(xié)議規(guī)定POST提交的數(shù)據(jù)必須放在消息主體中凿将,但協(xié)議并沒(méi)有規(guī)定數(shù)據(jù)必須使用什么編碼方式。實(shí)際上价脾,開(kāi)發(fā)者完全可以自己決定消息主體的格式牧抵,只要最后發(fā)送的 HTTP 請(qǐng)求滿足上面的格式就可以。

但是侨把,數(shù)據(jù)發(fā)送出去犀变,還要服務(wù)端解析成功才有意義妹孙。一般服務(wù)端語(yǔ)言如php、python等弛作,以及它們的framework涕蜂,都內(nèi)置了自動(dòng)解析常見(jiàn)數(shù)據(jù)格式的功能。服務(wù)端通常是根據(jù)請(qǐng)求頭(headers)中的Content-Type字段來(lái)獲知請(qǐng)求中的消息主體是用何種方式編碼映琳,再對(duì)主體進(jìn)行解析机隙。所以說(shuō)到POST提交數(shù)據(jù)方案,包含了Content-Type和消息主體編碼方式兩部分萨西。

2.1 application/x-www-form-urlencoded格式的POST請(qǐng)求

這應(yīng)該是最常見(jiàn)的 POST 提交數(shù)據(jù)的方式了有鹿。瀏覽器的原生表單,如果不設(shè)置enctype屬性谎脯,那么最終就會(huì)以application/x-www-form-urlencoded方式提交數(shù)據(jù)葱跋。Content-Type被指定為application/x-www-form-urlencoded,提交的數(shù)據(jù)按照 key1=val1&key2=val2的方式進(jìn)行編碼源梭,key和val都進(jìn)行了URL轉(zhuǎn)碼娱俺。

下面這個(gè)請(qǐng)求是簡(jiǎn)書進(jìn)入一篇文章頁(yè)面的時(shí)候,會(huì)自動(dòng)往服務(wù)器POST一個(gè)請(qǐng)求废麻,估計(jì)是統(tǒng)計(jì)文章被閱讀的次數(shù)等功能荠卷。具體看下面:

//發(fā)送的請(qǐng)求,刪除了cookie相關(guān)的部分
POST /notes/e15592ce40ae/mark_viewed.json HTTP/1.1
Host: www.reibang.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
X-CSRF-Token: vJvptva4Tqou/V3dd3nFCrcvRsb78FReHuIYZke5PVAnfR/tIAAMCfuaB2Z2/gaEohIZAsiEksUYyPqzg3DpSA==
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Referer: http://www.reibang.com/p/e15592ce40ae
Content-Length: 98
Connection: keep-alive
Cache-Control: max-age=0
//請(qǐng)求體

uuid=4e3abc0f-1824-4a5d-982f-7d9dee92d9cd&referrer=http%3A%2F%2Fwww.reibang.com%2Fu%2Fad726ba6935d

AFHTTPSessionManager實(shí)現(xiàn)上面這個(gè)application/x-www-form-urlencoded請(qǐng)求烛愧。

    AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    NSDictionary *params = @{
                             @"uuid":@"4e3abc0f-1824-4a5d-982f-7d9dee92d9cd",
                             @"referrer":@"http://www.reibang.com/p/e15592ce40ae"
                             };
    NSURLSessionDataTask *task = [manager POST:@"http://www.reibang.com//notes/e15592ce40ae/mark_viewed.json" parameters:params progress:^(NSProgress * _Nonnull uploadProgress) {
        NSLog(@"進(jìn)度更新");
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"返回?cái)?shù)據(jù):%@",responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"返回錯(cuò)誤:%@",error);
    }];
    [task resume];

2.2 multipart/form-data格式的POST請(qǐng)求

Multipart/form-data的基礎(chǔ)方法是POST , 也就是說(shuō)是由POST方法來(lái)組合實(shí)現(xiàn)的.
Multipart/form-data與POST方法的不同之處在于請(qǐng)求頭和請(qǐng)求體.
Multipart/form-data的請(qǐng)求頭必須包含一個(gè)特殊的頭信息 : Content-Type , 且其值也必須規(guī)定為multipart/form-data , 同時(shí)還需要規(guī)定一個(gè)內(nèi)容分割符用于分割請(qǐng)求體中的多個(gè)POST的內(nèi)容 , 如文件內(nèi)容和文本內(nèi)容自然需要分割開(kāi)來(lái) , 不然接收方就無(wú)法正常解析和還原這個(gè)文件了.
Multipart/form-data的請(qǐng)求體也是一個(gè)字符串 , 不過(guò)和post的請(qǐng)求體不同的是它的構(gòu)造方式 , post是簡(jiǎn)單的name=value值連接 , 而Multipart/form-data則是添加了分隔符等內(nèi)容的構(gòu)造體.

請(qǐng)求的頭部信息如下:

//其中xxxxx是我自定義的分隔符油宜,每個(gè)人都可以選擇自己的分隔符
Content-Type: multipart/form-data; boundary=xxxxx

下面我們來(lái)看一下一個(gè)我的Multipart/form-data請(qǐng)求體:

POST /uploadFile HTTP/1.1
Host: 這里是url,就不暴露了^_^
Content-Type: multipart/form-data; boundary=xxxxx
Connection: keep-alive
Accept: */*
User-Agent: AFNetWorking3.X%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/1 CFNetwork/808.2.16 Darwin/15.6.0
Content-Length: 32175
Accept-Language: en-us
Accept-Encoding: gzip, deflate

--xxxxx
Content-Disposition: form-data;name="file"

img.jpeg
--xxxxx
Content-Disposition: form-data;name="businessType"

CC_USER_CENTER
--xxxxx
Content-Disposition: form-data;name="fileType"

image
--xxxxx
Content-Disposition:form-data;name="file";filename="img1.jpeg"
Content-Type:image/png

這里是圖片數(shù)據(jù),太長(zhǎng)了.我就刪了

--xxxxx--

這個(gè)請(qǐng)求有三個(gè)參數(shù)file,businessType,fileType。比如file參數(shù)和他的值就通過(guò)如下格式傳輸:

--xxxxx
Content-Disposition: form-data;name="file"

img.jpeg

上面這種就是一個(gè)參數(shù)與之對(duì)應(yīng)的值怜姿。協(xié)議規(guī)定的就是這個(gè)格式慎冤,沒(méi)有為什么。我們可以看看圖片數(shù)據(jù)部分:

--xxxxx
Content-Disposition:form-data;name="file";filename="img1.jpeg"
Content-Type:image/png

這里是圖片數(shù)據(jù),太長(zhǎng)了.我就刪了

--xxxxx--

其中name="參數(shù)名" filename="文件名" 其中參數(shù)名這個(gè)要和接收方那邊相對(duì)應(yīng) 正常開(kāi)發(fā)中可以去問(wèn)服務(wù)器那邊 , 文件名是說(shuō)在服務(wù)器端保存成文件的名字 , 這個(gè)參數(shù)然并卵 , 因?yàn)橐话惴?wù)端會(huì)按照他們自己的要求去處理文件的存儲(chǔ).

下一行是指定類型 , 我這里示例中寫的是PNG圖片類型 , 這個(gè)可以根據(jù)你的實(shí)際需求的寫沧卢。如果我們要上傳多分圖片或者文件蚁堤,則只需要按照指定格式就可以了,比如下面就是上傳兩張圖片的請(qǐng)求:

POST /uploadFile HTTP/1.1
Host: 這里是url,就不暴露了^_^
Content-Type: multipart/form-data; boundary=xxxxx
Connection: keep-alive
Accept: */*
User-Agent: AFNetWorking3.X%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/1 CFNetwork/808.2.16 Darwin/15.6.0
Content-Length: 32175
Accept-Language: en-us
Accept-Encoding: gzip, deflate

--xxxxx
Content-Disposition: form-data;name="file"

img.jpeg
--xxxxx
Content-Disposition: form-data;name="businessType"

CC_USER_CENTER
--xxxxx
Content-Disposition: form-data;name="fileType"

image
--xxxxx
Content-Disposition:form-data;name="file";filename="img1.jpeg"
Content-Type:image/png

這里是圖片1數(shù)據(jù),太長(zhǎng)了.我就刪了
--xxxxx
Content-Disposition:form-data;name="file";filename="img2.jpeg"
Content-Type:image/png

這里是圖片1數(shù)據(jù),太長(zhǎng)了.我就刪了
--xxxxx--

下面是我Demo中一個(gè)multipart/form-data請(qǐng)求的實(shí)現(xiàn)代碼,分別用NSRULDataTaskAFHTTPSessionManager實(shí)現(xiàn),我們可以發(fā)現(xiàn)用第二種方法簡(jiǎn)便了很多但狭,因?yàn)锳FN已經(jīng)幫我們做好了拼接工作:

//方法一
- (IBAction)updatePic:(id)sender {
    //請(qǐng)求頭參數(shù)
    NSDictionary *dic = @{
                          @"businessType":@"CC_USER_CENTER",
                          @"fileType":@"image",
                          @"file":@"img.jpeg"
                          };
    //請(qǐng)求體圖片數(shù)據(jù)
    NSData *imageData = UIImagePNGRepresentation([UIImage imageNamed:@"1.png"]);
    //創(chuàng)建request
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:url]];
    //post方法
    [request setHTTPMethod:@"POST"];
    // 設(shè)置請(qǐng)求頭格式為Content-Type:multipart/form-data; boundary=xxxxx
    //[request setValue:@"multipart/form-data; boundary=xxxxx" forHTTPHeaderField:@"Content-Type"];
    AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc]initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    NSURLSessionDataTask *task = [manager POST:url parameters:dic constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        //請(qǐng)求體里面的參數(shù)
        NSDictionary *bodyDic = @{
                                  @"Content-Disposition":@"form-data;name=\"file\";filename=\"img.jpeg\"",
                                  @"Content-Type":@"image/png",
                                  };
        [formData appendPartWithHeaders:bodyDic body:imageData];
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        NSLog(@"下載進(jìn)度");
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"下載成功:%@",responseObject);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        NSLog(@"下載失敗%@",error);
    }];
    [task resume];
}
//方法二
- (IBAction)multipartformPost2:(id)sender {
    //參數(shù)
    NSDictionary *dic = @{
                          @"businessType":@"CC_USER_CENTER",
                          @"fileType":@"image",
                          @"file":@"img.jpeg"
                          };
    NSString *boundaryString = @"xxxxx";
    NSMutableString *str = [NSMutableString string];
    [dic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
        [str appendFormat:@"--%@\r\n",boundaryString];
        [str appendFormat:@"%@name=\"%@\"\r\n\r\n",@"Content-Disposition: form-data;",key];
        [str appendFormat:@"%@\r\n",obj];
    }];
    
     NSMutableData *requestMutableData=[NSMutableData data];

    [str appendFormat:@"--%@\r\n",boundaryString];
    [str appendFormat:@"%@:%@",@"Content-Disposition",@"form-data;"];
    [str appendFormat:@"%@=\"%@\";",@"name",@"file"];
    [str appendFormat:@"%@=\"%@\"\r\n",@"filename",@"img1.jpeg"];
    [str appendFormat:@"%@:%@\r\n\r\n",@"Content-Type",@"image/png"];
    //轉(zhuǎn)換成為二進(jìn)制數(shù)據(jù)
    [requestMutableData appendData:[str dataUsingEncoding:NSUTF8StringEncoding]];
    NSData *imageData = UIImagePNGRepresentation([UIImage imageNamed:@"1.png"]);
    //文件數(shù)據(jù)部分
    [requestMutableData appendData:imageData];
    //添加結(jié)尾boundary
    [requestMutableData appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n",boundaryString] dataUsingEncoding:NSUTF8StringEncoding]];
    //創(chuàng)建一個(gè)請(qǐng)求對(duì)象
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc]initWithURL:[NSURL URLWithString:url]];
    //post方法
    [request setHTTPMethod:@"POST"];
    // 設(shè)置請(qǐng)求頭格式為Content-Type:multipart/form-data; boundary=xxxxx
    [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@",boundaryString] forHTTPHeaderField:@"Content-Type"];
    //session
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    NSURLSessionDataTask *task = [session uploadTaskWithRequest:request fromData:requestMutableData completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSString *result = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"%@",result);
    }];
    [task resume];
}

Multipart/form-data格式的POST請(qǐng)求總結(jié):

  • 文件類型參數(shù)中name="參數(shù)名"一定要和服務(wù)端對(duì)應(yīng), 開(kāi)發(fā)的時(shí)候 , 可以問(wèn)服務(wù)端人員披诗,我這里是file
  • 上傳文件的數(shù)據(jù)部分使用二進(jìn)制數(shù)據(jù)(NSData)拼接熟空。
  • 上邊界部分和下邊界部分的字符串 , 最后都要轉(zhuǎn)換成二進(jìn)制數(shù)據(jù)(NSData) , 和文件部分的二進(jìn)制數(shù)據(jù)拼接在一起 , 作為請(qǐng)求體發(fā)送給服務(wù)器。
  • 每一行末尾需要有一定的`\r\n·搞莺。

2.3 application/json格式的POST請(qǐng)求

接下來(lái)我將常使用NSURLSessionDataTask做一個(gè)application/json的POST請(qǐng)求息罗。并且請(qǐng)求體數(shù)據(jù)我存儲(chǔ)在一個(gè)test.txt文件中,從文件中讀取出來(lái)然后上傳才沧。

//test.txt文件內(nèi)容
{"name":"huang","phone":"124"}

通過(guò)抓包軟件我的請(qǐng)求如下迈喉,和其他POST請(qǐng)求原理一樣绍刮,只是拼接請(qǐng)求體的方式不一樣,并且更具不同格式的請(qǐng)求體挨摸,設(shè)置不同的Content-Type

POST /posts HTTP/1.1
Host: jsonplaceholder.typicode.com
Content-Type: application/json
Connection: keep-alive
Accept: application/json
User-Agent: AFNetWorking3.X%E6%BA%90%E7%A0%81%E9%98%85%E8%AF%BB/1 CFNetwork/808.2.16 Darwin/15.6.0
Content-Length: 31
Accept-Language: en-us
Accept-Encoding: gzip, deflate

{"name":"huang","phone":"124"}

下面是我Demo的具體實(shí)現(xiàn)

- (IBAction)applicationjsonPOST2:(id)sender {
    NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://jsonplaceholder.typicode.com/posts"]];
    //指請(qǐng)求體的類型孩革。由于我們test.txt里面的文件是json格式的字符串。所以我這里指定為`application/json`
    [request addValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
    [request addValue:@"application/json" forHTTPHeaderField:@"Accept"];
    [request setHTTPMethod:@"POST"];
    [request setCachePolicy:NSURLRequestReloadIgnoringCacheData];
    [request setTimeoutInterval:20];
    NSString *path = [[NSBundle mainBundle] pathForResource:@"test" ofType:@"txt"];
    NSURL *url = [NSURL URLWithString:[path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    //使用Block來(lái)處理返回?cái)?shù)據(jù)
    NSURLSessionDataTask *task = [session uploadTaskWithRequest:request fromFile:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
        NSString *result = [[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding];
        NSLog(@"%@",result);
    }];
    [task resume];
}

AFHTTPSessionManager分析

上面主要講了對(duì)POST請(qǐng)求的分析得运,主要是AFHTTPSessionManager并沒(méi)有多少邏輯,他主要是調(diào)用AFURLSessionManager的實(shí)現(xiàn)膝蜈。另外就是通過(guò)baseURL改變了url的拼接過(guò)程。下面我就抽出他們的不同點(diǎn)分析一下:

1 首先多了一個(gè)屬性

@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer;

這個(gè)屬性的主要作用就是幫我們拼接請(qǐng)求頭和請(qǐng)求體熔掺,從上面的Demo我們發(fā)現(xiàn)很多請(qǐng)求的拼接工作都通過(guò)requestSerializer處理了饱搏。如果我們不手動(dòng)設(shè)置,默認(rèn)是一個(gè)AFHTTPRequestSerializer對(duì)象置逻。具體可以去初始化方法里面看到推沸。

2 重寫了securityPolicy這個(gè)屬性的setter方法,增加對(duì)于SSLPinningMode的異常處理。

- (void)setSecurityPolicy:(AFSecurityPolicy *)securityPolicy {
    //增加對(duì)于SSLPinningMode的異常處理券坞。
    if (securityPolicy.SSLPinningMode != AFSSLPinningModeNone && ![self.baseURL.scheme isEqualToString:@"https"]) {
        NSString *pinningMode = @"Unknown Pinning Mode";
        switch (securityPolicy.SSLPinningMode) {
            case AFSSLPinningModeNone:        pinningMode = @"AFSSLPinningModeNone"; break;
            case AFSSLPinningModeCertificate: pinningMode = @"AFSSLPinningModeCertificate"; break;
            case AFSSLPinningModePublicKey:   pinningMode = @"AFSSLPinningModePublicKey"; break;
        }
        NSString *reason = [NSString stringWithFormat:@"A security policy configured with `%@` can only be applied on a manager with a secure base URL (i.e. https)", pinningMode];
        @throw [NSException exceptionWithName:@"Invalid Security Policy" reason:reason userInfo:nil];
    }
    //調(diào)用`AFURLSessionManager`的`securityPolicy`屬性的setter方法鬓催。
    [super setSecurityPolicy:securityPolicy];
}

3 NSCopying和NSSecureCoding協(xié)議的實(shí)現(xiàn)過(guò)程

NSCopyingNSSecureCoding協(xié)議的實(shí)現(xiàn)過(guò)程添加了對(duì)requestSerializer,responseSerializer,securityPolicy這三個(gè)屬性的復(fù)制。也就是說(shuō)恨锚,用copy方法復(fù)制的manager宇驾,這三個(gè)屬性的配置跟著一起復(fù)制。而父類AFURSSessionManager只實(shí)現(xiàn)了對(duì)configuration的復(fù)制眠冈。

+ (BOOL)supportsSecureCoding {
    return YES;
}
- (instancetype)initWithCoder:(NSCoder *)decoder {
    NSURL *baseURL = [decoder decodeObjectOfClass:[NSURL class] forKey:NSStringFromSelector(@selector(baseURL))];
    //獲取當(dāng)前manager的NSURLSessionConfiguration
    NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"];
    if (!configuration) {
        NSString *configurationIdentifier = [decoder decodeObjectOfClass:[NSString class] forKey:@"identifier"];
        if (configurationIdentifier) {
        //iOS7和iOS8初始化NSURLSessionConfiguration方法不一樣飞苇。所以要分開(kāi)處理
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1100)
            configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:configurationIdentifier];
#else
            configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:configurationIdentifier];
#endif
        }
    }
    //初始化一個(gè)新的manager
    self = [self initWithBaseURL:baseURL sessionConfiguration:configuration];
    if (!self) {
        return nil;
    }
    //添加了對(duì)`requestSerializer`,`responseSerializer`,`securityPolicy`這三個(gè)屬性的接檔。
    self.requestSerializer = [decoder decodeObjectOfClass:[AFHTTPRequestSerializer class] forKey:NSStringFromSelector(@selector(requestSerializer))];
    self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))];
    AFSecurityPolicy *decodedPolicy = [decoder decodeObjectOfClass:[AFSecurityPolicy class] forKey:NSStringFromSelector(@selector(securityPolicy))];
    if (decodedPolicy) {
        self.securityPolicy = decodedPolicy;
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)coder {
    [super encodeWithCoder:coder];
    //添加對(duì)baseURL屬性的歸檔
    [coder encodeObject:self.baseURL forKey:NSStringFromSelector(@selector(baseURL))];
    if ([self.session.configuration conformsToProtocol:@protocol(NSCoding)]) {
        [coder encodeObject:self.session.configuration forKey:@"sessionConfiguration"];
    } else {
        [coder encodeObject:self.session.configuration.identifier forKey:@"identifier"];
    }
    //添加了對(duì)`requestSerializer`,`responseSerializer`,`securityPolicy`這三個(gè)屬性的歸檔蜗顽。
    [coder encodeObject:self.requestSerializer forKey:NSStringFromSelector(@selector(requestSerializer))];
    [coder encodeObject:self.responseSerializer forKey:NSStringFromSelector(@selector(responseSerializer))];
    [coder encodeObject:self.securityPolicy forKey:NSStringFromSelector(@selector(securityPolicy))];
}

#pragma mark - NSCopying
- (instancetype)copyWithZone:(NSZone *)zone {
    AFHTTPSessionManager *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL sessionConfiguration:self.session.configuration];
    //添加了對(duì)`requestSerializer`,`responseSerializer`,`securityPolicy`這三個(gè)屬性的復(fù)制布卡。
    HTTPClient.requestSerializer = [self.requestSerializer copyWithZone:zone];
    HTTPClient.responseSerializer = [self.responseSerializer copyWithZone:zone];
    HTTPClient.securityPolicy = [self.securityPolicy copyWithZone:zone];
    return HTTPClient;
}

4 HEAD和PUT等方法的實(shí)現(xiàn)

我在這里不準(zhǔn)備深入講這兩個(gè)方法是如何實(shí)現(xiàn)的,因?yàn)?code>AFHTTPSessionManager主要通過(guò)他的requestSerializer屬性來(lái)實(shí)現(xiàn)對(duì)HEADPUT等請(qǐng)求的拼接雇盖。我準(zhǔn)備分析AFHTTPRequestSerializer的時(shí)候再看這一塊是如何實(shí)現(xiàn)的忿等。

 //通過(guò)requestSerializer屬性來(lái)拼接request對(duì)象。
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];

最后原文地址,demo地址崔挖。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末贸街,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子狸相,更是在濱河造成了極大的恐慌薛匪,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件脓鹃,死亡現(xiàn)場(chǎng)離奇詭異逸尖,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門娇跟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)岩齿,“玉大人,你說(shuō)我怎么就攤上這事苞俘№锷颍” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵吃谣,是天一觀的道長(zhǎng)乞封。 經(jīng)常有香客問(wèn)我,道長(zhǎng)基协,這世上最難降的妖魔是什么歌亲? 我笑而不...
    開(kāi)封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮澜驮,結(jié)果婚禮上陷揪,老公的妹妹穿的比我還像新娘。我一直安慰自己杂穷,他們只是感情好悍缠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著耐量,像睡著了一般飞蚓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上廊蜒,一...
    開(kāi)封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天趴拧,我揣著相機(jī)與錄音,去河邊找鬼山叮。 笑死著榴,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的屁倔。 我是一名探鬼主播脑又,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼锐借!你這毒婦竟也來(lái)了问麸?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤钞翔,失蹤者是張志新(化名)和其女友劉穎严卖,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體布轿,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡哮笆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年俺亮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片疟呐。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖东且,靈堂內(nèi)的尸體忽然破棺而出启具,到底是詐尸還是另有隱情,我是刑警寧澤珊泳,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布鲁冯,位于F島的核電站,受9級(jí)特大地震影響色查,放射性物質(zhì)發(fā)生泄漏薯演。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一秧了、第九天 我趴在偏房一處隱蔽的房頂上張望跨扮。 院中可真熱鬧,春花似錦验毡、人聲如沸衡创。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)璃氢。三九已至,卻和暖如春狮辽,著一層夾襖步出監(jiān)牢的瞬間一也,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工喉脖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留椰苟,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓动看,卻偏偏與公主長(zhǎng)得像尊剔,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子菱皆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容