前言
序列化,百度百科的解釋摘抄如下:
序列化 (Serialization)將對(duì)象的狀態(tài)信息轉(zhuǎn)換為可以存儲(chǔ)或傳輸?shù)男问降倪^程。在序列化期間挽霉,對(duì)象將其當(dāng)前狀態(tài)寫入到臨時(shí)或持久性存儲(chǔ)區(qū)写穴。以后,可以通過從存儲(chǔ)區(qū)中讀取或反序列化對(duì)象的狀態(tài)判没,重新創(chuàng)建該對(duì)象。
1隅茎、以某種存儲(chǔ)形式使自定義對(duì)象持久化澄峰;
2、將對(duì)象從一個(gè)地方傳遞到另一個(gè)地方辟犀。
3俏竞、使程序更具維護(hù)性。
簡(jiǎn)單點(diǎn)說就是將對(duì)象轉(zhuǎn)換為二進(jìn)制流堂竟,以便存儲(chǔ)或傳輸魂毁,且日后也能從二進(jìn)制流轉(zhuǎn)換回對(duì)象。 所以我們今天要說的請(qǐng)求序列化跃捣,說到底就是造一個(gè)可以在網(wǎng)絡(luò)上傳遞(被序列化)的漱牵、合法可用的請(qǐng)求。這其中就包括了參數(shù)的處理和請(qǐng)求頭的設(shè)置等疚漆。不管怎樣的代碼酣胀,萬變不離其宗,它的核心就是這個(gè)知識(shí)點(diǎn)娶聘。所以理解了這個(gè)闻镶,再去看代碼就容易多了。
我們知道丸升,GET
請(qǐng)求和POST
請(qǐng)求對(duì)于參數(shù)是不同的處理铆农。GET
請(qǐng)求是多個(gè)參數(shù)之間以&
相連,且單個(gè)參數(shù)的鍵值間以=
連接狡耻,并將參數(shù)以墩剖?
開頭猴凹,經(jīng)過編碼再追加在url
后面,而POST
卻是將其放入請(qǐng)求體HTTPBody
的岭皂。
另外一個(gè)HTTP
連接的請(qǐng)求頭HTTPHeaderField
設(shè)置也是非常重要的郊霎,它提供了很多字段,用于不同場(chǎng)景爷绘,不同特征下的使用书劝。
生成請(qǐng)求request
的地方是在AFHTTPSessionManager
中,當(dāng)時(shí)我們說了該類有名為序列化器的屬性requestSerializer
土至,然后調(diào)用該序列化器的方法生成了一個(gè)request购对。當(dāng)時(shí),因?yàn)檫@是AFHTTPRequestSerializer
類中的方法陶因,所以對(duì)于具體實(shí)現(xiàn)沒有研究骡苞。今天我們的工作就是這個(gè)。
源碼
先來看頭文件AFHTTPRequestSerializer.h
坑赡。它繼承自NSObject
烙如,實(shí)現(xiàn)了AFURLRequestSerialization
協(xié)議么抗。
首先看頭文件中定義的屬性:
@property (nonatomic, assign) NSStringEncoding stringEncoding;
@property (nonatomic, assign) BOOL allowsCellularAccess; // 是否允許使用蜂窩網(wǎng)絡(luò)毅否,默認(rèn)YES
@property (nonatomic, assign) NSURLRequestCachePolicy cachePolicy; // 緩存策略
@property (nonatomic, assign) BOOL HTTPShouldHandleCookies; // 是否處理Cookie
@property (nonatomic, assign) BOOL HTTPShouldUsePipelining; // 是否開啟管線化
@property (nonatomic, assign) NSURLRequestNetworkServiceType networkServiceType;
@property (nonatomic, assign) NSTimeInterval timeoutInterval;
@property (readonly, nonatomic, strong) NSDictionary <NSString *, NSString *> *HTTPRequestHeaders;
@property (nonatomic, strong) NSSet <NSString *> *HTTPMethodsEncodingParametersInURI;
stringEncoding
意為序列化參數(shù)時(shí)的字符串編碼,默認(rèn)是NSUTF8StringEncoding
蝇刀;
HTTPRequestHeaders
是個(gè)字典螟加,意為即將被序列化的HTTP的請(qǐng)求頭。默認(rèn)包括Accept-Language
和User-Agent
等字段吞琐;
HTTPMethodsEncodingParametersInURI
是個(gè)集合對(duì)象捆探,它表示序列化時(shí)參數(shù)被追加在url里的請(qǐng)求方式的集合,想想也知道站粟,它的元素應(yīng)該是GET
黍图、Head
。
其他幾個(gè)屬性都比較好理解奴烙,而且注釋寫得很清楚了助被,不解釋了。
接著看在頭文件中暴露的前幾個(gè)方法:
+ (instancetype)serializer;
- (void)setValue:(nullable NSString *)value
forHTTPHeaderField:(NSString *)field;
- (nullable NSString *)valueForHTTPHeaderField:(NSString *)field;
- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username
password:(NSString *)password;
- (void)clearAuthorizationHeader;
- (void)setQueryStringSerializationWithStyle:(AFHTTPRequestQueryStringSerializationStyle)style;
- (void)setQueryStringSerializationWithBlock:(nullable NSString * (^)(NSURLRequest *request, id parameters, NSError * __autoreleasing *error))block;
首先是初始化方法切诀,return一個(gè)該類的實(shí)例對(duì)象揩环;然后是兩個(gè)對(duì)請(qǐng)求頭字典操作的兩個(gè)方法;再接著是兩個(gè)關(guān)于登錄認(rèn)證的方法幅虑;然后是一個(gè)設(shè)置序列化類型的方法丰滑,代表遵循什么樣的規(guī)則進(jìn)行queryString轉(zhuǎn)換。參數(shù)是個(gè)枚舉倒庵,但是這個(gè)枚舉只有一個(gè)值AFHTTPRequestQueryStringDefaultStyle
褒墨。最后一個(gè)方法提供了以block形式自定義queryString轉(zhuǎn)換的接口炫刷,也就是說可以通過block回調(diào)的方式讓調(diào)用者以自己的方式完成queryString的轉(zhuǎn)換。
最后就剩下三個(gè)核心方法了郁妈。其中第一個(gè)方法便是我們?cè)谇懊嬉呀?jīng)接觸過的柬唯,由HTTP method
、URLString
圃庭、parameters
返回一個(gè)請(qǐng)求request
锄奢。
下面代碼注釋非常占篇幅,但是注釋的很好剧腻,舍不得刪拘央。
Creates an
NSMutableURLRequest
object with the specified HTTP method and URL string.
If the HTTP method is
GET
,HEAD
, orDELETE
, the parameters will be used to construct a url-encoded query string that is appended to the request's URL. Otherwise, the parameters will be encoded according to the value of theparameterEncoding
property, and set as the request body.
/**
Creates an `NSMutableURLRequest` object with the specified HTTP method and URL string.
If the HTTP method is `GET`, `HEAD`, or `DELETE`, the parameters will be used to construct a url-encoded query string that is appended to the request's URL. Otherwise, the parameters will be encoded according to the value of the `parameterEncoding` property, and set as the request body.
@param method The HTTP method for the request, such as `GET`, `POST`, `PUT`, or `DELETE`. This parameter must not be `nil`.
@param URLString The URL string used to create the request URL.
@param parameters The parameters to be either set as a query string for `GET` requests, or the request HTTP body.
@param error The error that occurred while constructing the request.
@return An `NSMutableURLRequest` object.
*/
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(nullable id)parameters
error:(NSError * _Nullable __autoreleasing *)error;
/**
Creates an `NSMutableURLRequest` object with the specified HTTP method and URLString, and constructs a `multipart/form-data` HTTP body, using the specified parameters and multipart form data block. See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2
Multipart form requests are automatically streamed, reading files directly from disk along with in-memory data in a single HTTP body. The resulting `NSMutableURLRequest` object has an `HTTPBodyStream` property, so refrain from setting `HTTPBodyStream` or `HTTPBody` on this request object, as it will clear out the multipart form body stream.
@param method The HTTP method for the request. This parameter must not be `GET` or `HEAD`, or `nil`.
@param URLString The URL string used to create the request URL.
@param parameters The parameters to be encoded and set in the request HTTP body.
@param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol.
@param error The error that occurred while constructing the request.
@return An `NSMutableURLRequest` object
*/
- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(nullable NSDictionary <NSString *, id> *)parameters
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
error:(NSError * _Nullable __autoreleasing *)error;
/**
Creates an `NSMutableURLRequest` by removing the `HTTPBodyStream` from a request, and asynchronously writing its contents into the specified file, invoking the completion handler when finished.
@param request The multipart form request. The `HTTPBodyStream` property of `request` must not be `nil`.
@param fileURL The file URL to write multipart form contents to.
@param handler A handler block to execute.
@discussion There is a bug in `NSURLSessionTask` that causes requests to not send a `Content-Length` header when streaming contents from an HTTP body, which is notably problematic when interacting with the Amazon S3 webservice. As a workaround, this method takes a request constructed with `multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:error:`, or any other request with an `HTTPBodyStream`, writes the contents to the specified file and returns a copy of the original request with the `HTTPBodyStream` property set to `nil`. From here, the file can either be passed to `AFURLSessionManager -uploadTaskWithRequest:fromFile:progress:completionHandler:`, or have its contents read into an `NSData` that's assigned to the `HTTPBody` property of the request.
@see https://github.com/AFNetworking/AFNetworking/issues/1398
*/
- (NSMutableURLRequest *)requestWithMultipartFormRequest:(NSURLRequest *)request
writingStreamContentsToFile:(NSURL *)fileURL
completionHandler:(nullable void (^)(NSError * _Nullable error))handler;
頭文件中基本就是以上東西,現(xiàn)在我們應(yīng)該如饑似渴书在,迫不及待的開始看.m文件了灰伟。
@interface AFHTTPRequestSerializer ()
@property (readwrite, nonatomic, strong) NSMutableSet *mutableObservedChangedKeyPaths;
@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableHTTPRequestHeaders;
@property (readwrite, nonatomic, strong) dispatch_queue_t requestHeaderModificationQueue;
@property (readwrite, nonatomic, assign) AFHTTPRequestQueryStringSerializationStyle queryStringSerializationStyle;
@property (readwrite, nonatomic, copy) AFQueryStringSerializationBlock queryStringSerialization;
@end
@implementation AFHTTPRequestSerializer
+ (instancetype)serializer {
return [[self alloc] init];
}
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
self.stringEncoding = NSUTF8StringEncoding;
self.mutableHTTPRequestHeaders = [NSMutableDictionary dictionary];
self.requestHeaderModificationQueue = dispatch_queue_create("requestHeaderModificationQueue", DISPATCH_QUEUE_CONCURRENT);
// Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
NSMutableArray *acceptLanguagesComponents = [NSMutableArray array];
[[NSLocale preferredLanguages] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
float q = 1.0f - (idx * 0.1f);
[acceptLanguagesComponents addObject:[NSString stringWithFormat:@"%@;q=%0.1g", obj, q]];
*stop = q <= 0.5f;
}];
[self setValue:[acceptLanguagesComponents componentsJoinedByString:@", "] forHTTPHeaderField:@"Accept-Language"];
NSString *userAgent = nil;
#if TARGET_OS_IOS
// User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43
userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]];
#elif TARGET_OS_WATCH
// User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43
userAgent = [NSString stringWithFormat:@"%@/%@ (%@; watchOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[WKInterfaceDevice currentDevice] model], [[WKInterfaceDevice currentDevice] systemVersion], [[WKInterfaceDevice currentDevice] screenScale]];
#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
userAgent = [NSString stringWithFormat:@"%@/%@ (Mac OS X %@)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[NSProcessInfo processInfo] operatingSystemVersionString]];
#endif
if (userAgent) {
if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) {
NSMutableString *mutableUserAgent = [userAgent mutableCopy];
if (CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin; Latin-ASCII; [:^ASCII:] Remove", false)) {
userAgent = mutableUserAgent;
}
}
[self setValue:userAgent forHTTPHeaderField:@"User-Agent"];
}
// HTTP Method Definitions; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html
self.HTTPMethodsEncodingParametersInURI = [NSSet setWithObjects:@"GET", @"HEAD", @"DELETE", nil];
// 在AFHTTPRequestSerializer的初始化方法init中就初始化了集合mutableObservedChangedKeyPaths。并且遍歷AFHTTPRequestSerializerObservedKeyPaths數(shù)組儒旬,為每一項(xiàng)添加觀察
self.mutableObservedChangedKeyPaths = [NSMutableSet set];
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
[self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext];
}
}
return self;
}
- (void)dealloc {
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self respondsToSelector:NSSelectorFromString(keyPath)]) {
[self removeObserver:self forKeyPath:keyPath context:AFHTTPRequestSerializerObserverContext];
}
}
}
首先是初始化方法栏账,乍看這里感覺好復(fù)雜,其實(shí)一點(diǎn)不復(fù)雜栈源。初始化方法說到底就是初始化挡爵。它首先初始化了幾個(gè)屬性。stringEncoding
屬性初始化默認(rèn)為NSUTF8StringEncoding
甚垦;然后初始化了用于裝HTTP請(qǐng)求頭屬性的字典mutableHTTPRequestHeaders
茶鹃;還初始化了修改請(qǐng)求頭時(shí)而專門創(chuàng)建的隊(duì)列requestHeaderModificationQueue
。
接下來是一大串亂糟糟的代碼艰亮,仔細(xì)看就明白了:此時(shí)既然已初始化了裝置請(qǐng)求頭屬性的字典闭翩,那不就可以先設(shè)置一些可以設(shè)置的請(qǐng)求頭屬性了。即Accept-Language
和User-Agent
迄埃。
初始化方法的最后為序列化需要觀察的屬性添加了監(jiān)聽疗韵。這里是指哪些需要觀察的屬性字段呢?從上面代碼可以看到侄非,它是由一個(gè)C函數(shù)獲取的AFHTTPRequestSerializerObservedKeyPaths()
蕉汪,返回了一個(gè)數(shù)組,數(shù)組便是需要觀察的屬性字段的數(shù)組彩库。
而當(dāng)我們?cè)O(shè)置了這些HTTP配置屬性的值時(shí)肤无,就會(huì)觸發(fā)觀察回調(diào)的方法,在此方面里將該屬性字符串放入了mutableObservedChangedKeyPaths數(shù)組骇钦。代碼如下:
// 當(dāng)我們?cè)O(shè)置了這些HTTP配置屬性的值時(shí)宛渐,就會(huì)觸發(fā)觀察回調(diào)方法。并將該屬性字符串放入mutableObservedChangedKeyPaths集合
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(__unused id)object
change:(NSDictionary *)change
context:(void *)context
{
if (context == AFHTTPRequestSerializerObserverContext) {
if ([change[NSKeyValueChangeNewKey] isEqual:[NSNull null]]) {
[self.mutableObservedChangedKeyPaths removeObject:keyPath];
} else {
[self.mutableObservedChangedKeyPaths addObject:keyPath];
}
}
}
接著往下看:
- (NSDictionary *)HTTPRequestHeaders {
NSDictionary __block *value;
dispatch_sync(self.requestHeaderModificationQueue, ^{
value = [NSDictionary dictionaryWithDictionary:self.mutableHTTPRequestHeaders];
});
return value;
}
- (void)setValue:(NSString *)value
forHTTPHeaderField:(NSString *)field
{
dispatch_barrier_async(self.requestHeaderModificationQueue, ^{
[self.mutableHTTPRequestHeaders setValue:value forKey:field];
});
}
- (NSString *)valueForHTTPHeaderField:(NSString *)field {
NSString __block *value;
dispatch_sync(self.requestHeaderModificationQueue, ^{
value = [self.mutableHTTPRequestHeaders valueForKey:field];
});
return value;
}
- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username
password:(NSString *)password
{
NSData *basicAuthCredentials = [[NSString stringWithFormat:@"%@:%@", username, password] dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64AuthCredentials = [basicAuthCredentials base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0];
[self setValue:[NSString stringWithFormat:@"Basic %@", base64AuthCredentials] forHTTPHeaderField:@"Authorization"];
}
- (void)clearAuthorizationHeader {
dispatch_barrier_async(self.requestHeaderModificationQueue, ^{
[self.mutableHTTPRequestHeaders removeObjectForKey:@"Authorization"];
});
}
#pragma mark -
- (void)setQueryStringSerializationWithStyle:(AFHTTPRequestQueryStringSerializationStyle)style {
self.queryStringSerializationStyle = style;
self.queryStringSerialization = nil;
}
- (void)setQueryStringSerializationWithBlock:(NSString *(^)(NSURLRequest *, id, NSError *__autoreleasing *))block {
self.queryStringSerialization = block;
}
上面這些代碼沒什么可說的,接著往下看窥翩,就到了最核心的方法了:
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(method);
NSParameterAssert(URLString);
NSURL *url = [NSURL URLWithString:URLString];
NSParameterAssert(url);
NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url];
mutableRequest.HTTPMethod = method;
/*
為該HTTP的request設(shè)置配置屬性
方法AFHTTPRequestSerializerObservedKeyPaths()返回一個(gè)數(shù)組业岁,代表我們需要關(guān)注的HTTP配置屬性。
而mutableObservedChangedKeyPaths集合代表我們已設(shè)置的配置屬性寇蚊,
*/
for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) {
if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) {
[mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath];
}
}
/*
將傳入的parameters進(jìn)行編碼笔时,添加到request中
*/
mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy];
return mutableRequest;
}
開始閱讀該方法≌贪叮可以看到允耿,首先是對(duì)幾個(gè)參數(shù)的斷言。然后以URLString
生成url
扒怖,再以url
生成mutableRequest
较锡,并為其該HTTP請(qǐng)求設(shè)置配置屬性。然后它是將最核心的模塊封裝在了一個(gè)本類的方法里盗痒。我們跳入該方法蚂蕴,準(zhǔn)備繼續(xù)閱讀,此時(shí)發(fā)現(xiàn)不光本類中有這個(gè)方法俯邓,它的幾個(gè)子類中也實(shí)現(xiàn)了該方法骡楼。原來這個(gè)方法便是定義在AFURLRequestSerialization
協(xié)議中的方法。在不同的子類中有不同的實(shí)現(xiàn)稽鞭,用以實(shí)現(xiàn)不同的功能鸟整。下面是本類中該方法的實(shí)現(xiàn):
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(request);
NSMutableURLRequest *mutableRequest = [request mutableCopy];
/*
1.為request設(shè)置請(qǐng)求頭
*/
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];
/*
2.參數(shù)序列化處理(將參數(shù)字典解析為url query)
*/
NSString *query = nil;
if (parameters) {
// 若自定義了queryStringSerialization,那么就使用自定義的queryStringSerialization構(gòu)建方式
if (self.queryStringSerialization)
{
NSError *serializationError;
query = self.queryStringSerialization(request, parameters, &serializationError); // 通過queryStringSerialization構(gòu)建query字符串
if (serializationError) {
if (error) {
*error = serializationError;
}
return nil;
}
}
else
{
switch (self.queryStringSerializationStyle) {
case AFHTTPRequestQueryStringDefaultStyle:
query = AFQueryStringFromParameters(parameters); // 由參數(shù)生成url的query部分
break;
}
}
}
// HTTPMethodsEncodingParametersInURI是個(gè)NSSet川慌,裝了"GET"吃嘿、"HEAD"祠乃、"DELETE"請(qǐng)求方式(在該類的初始化方法里初始化了)梦重,因?yàn)檫@幾個(gè)請(qǐng)求方式的query是直接拼接在url后面的。
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
if (query && query.length > 0) {
mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]];
}
}
else // 若請(qǐng)求方式為"POST"亮瓷、"PUT"等琴拧,則需要將query設(shè)置到http body上
{
// #2864: an empty string is a valid x-www-form-urlencoded payload
if (!query) {
query = @"";
}
if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
[mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
}
[mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]]; // 將query string編碼
}
return mutableRequest;
}
該方法里的脈絡(luò)很清晰,分為兩個(gè)步驟嘱支。第一步便是為request設(shè)置請(qǐng)求頭屬性蚓胸;第二步是參數(shù)序列化處理:先看是否實(shí)現(xiàn)自定義的序列化處理block,若有除师,則調(diào)用自定義的block沛膳,讓使用者自己實(shí)現(xiàn)參數(shù)序列化;若無汛聚,則調(diào)用AFQueryStringFromParameters()
方法锹安,由參數(shù)字典轉(zhuǎn)換為query string。關(guān)于這個(gè)函數(shù)如何將字典解析為query string的釋義,這篇文章已經(jīng)解釋得很好:AFNetworking源碼閱讀(二)叹哭∪趟危總之,現(xiàn)在有了query string了风罩,但還是要根據(jù)HTTP method的不同糠排,將其放在正確的位置上。方法里接下來的代碼就是完成這部分的超升。
值得注意的是在HTTP method為POST
等其他時(shí)入宦,它設(shè)置Content-Type
為application/x-www-form-urlencoded
,這個(gè)代表什么意思呢室琢?我趕緊百度了下云石。收集了以下干貨資料:
四種常見的 POST 提交數(shù)據(jù)方式
HTTP協(xié)議之multipart/form-data請(qǐng)求分析
關(guān)于 Content-Type:application/x-www-form-urlencoded 和 Content-Type:multipart/related
結(jié)尾
剛說到了Content-Type
了,但時(shí)間不早了研乒,明天把這部分補(bǔ)充完整汹忠。