獲取NSURLResponse的HTTPVersion

一、需求背景

NSURLProtocol可以攔截UIWebView/WKWebView里的請求,公司的產(chǎn)品需要將攔劫到的HTTPS請求的URL的Host改成我們自己特定的Host,然后在請求頭里帶上原始域名給我們的節(jié)點(diǎn)殉簸,節(jié)點(diǎn)再以原始域名去訪問源站。我們稱之為HTTPS域名收斂。

域名被收斂之后面臨著一個問題略就,就是網(wǎng)頁里的html/css/js等文件被收斂之后,里面很多用相對地址編碼的資源被WebView加載時域名也變成了我們那個特定域名晃酒,這樣這些資源的原始域名就丟失了表牢,導(dǎo)致WebView里很多資源加載失敗。問題的解決方法是在NSURLProtocol里做域名收斂收到NSHTTPURLResponse的時候贝次,將它的URL的Host還原成原來的域名崔兴。

二、修改NSHTTPURLResponse的URL

NSHTTPURLResponse的URL屬性是只讀的蛔翅,也沒有被KVC敲茄,我們無法簡單的去直接修改它。所以只能根據(jù)原來的Response重新再構(gòu)造出一個新的URL不一樣的Response山析。NSHTTPURLResponse初始化方法如下

- (nullable instancetype)initWithURL:(NSURL *)url
                        statusCode:(NSInteger)statusCode
                         HTTPVersion:(nullable NSString *)HTTPVersion
                        headerFields:(nullable NSDictionary<NSString *, NSString *> *)headerFields;

構(gòu)造NSHTTPURLResponse所需的其他參數(shù)都好說堰燎,唯獨(dú)HTTPVersion這個參數(shù)我們無法直接得到,也就是沒有從原來那個NSHTTPURLResponse獲取HTTPVersion的Public API或者Private API笋轨。

三秆剪、獲取NSURLResponse的HTTPVersion

查資料后知道NSURLResponse是基于_CFURLResponse這個結(jié)構(gòu)體實(shí)現(xiàn)的

typedef struct _CFURLResponse {
    CFRuntimeBase _base;
    CFAbsoluteTime creationTime;
    CFURLRef url;
    CFStringRef mimeType;
    int64_t expectedLength;
    CFStringRef textEncoding;
    CFIndex statusCode;
    CFStringRef httpVersion;
    CFDictionaryRef headerFields;
    Boolean isHTTPResponse;

    OSSpinLock parsedHeadersLock;
    ParsedHeaders* parsedHeaders;
} _CFURLResponse;

typedef const struct _CFURLResponse* CFURLResponseRef;

你可以通過以下代碼從NSURLResponse中獲取到這個結(jié)構(gòu)體

SEL selector = NSSelectorFromString(@"_CFURLResponse");
CFTypeRef response = CFBridgingRetain([response performSelector:selector]);
CFShow(response);

拿到CFURLResponseRef赊淑,又要怎么從它獲取到httpVersion呢?無意間又發(fā)現(xiàn)下面這個函數(shù)可以將CFURLResponseRef轉(zhuǎn)化為CFHTTPMessageRef

CFHTTPMessageRef CFURLResponseGetHTTPResponse(CFURLResponseRef);

而下面這個函數(shù)又可以從CFHTTPMessageRef中獲取到我們想要的HttpVersion

CFStringRef CFHTTPMessageCopyVersion(CFHTTPMessageRef message);

四仅讽、示例代碼

#import <dlfcn.h>
#import "NSURLResponse+Help.h"

@implementation NSURLResponse (Help)

typedef CFHTTPMessageRef (*MYURLResponseGetHTTPResponse)(CFURLRef response);

- (NSString *)getHTTPVersion {
    NSURLResponse *response = self;
    NSString *version;

    // 獲取CFURLResponseGetHTTPResponse的函數(shù)實(shí)現(xiàn)
    NSString *funName = @"CFURLResponseGetHTTPResponse";
    MYURLResponseGetHTTPResponse originURLResponseGetHTTPResponse =
        dlsym(RTLD_DEFAULT, [funName UTF8String]);

    SEL theSelector = NSSelectorFromString(@"_CFURLResponse");
    if ([response respondsToSelector:theSelector] &&
        NULL != originURLResponseGetHTTPResponse) {
        // 獲取NSURLResponse的_CFURLResponse
        CFTypeRef cfResponse = CFBridgingRetain([response performSelector:theSelector]);
        if (NULL != cfResponse) {
            // 將CFURLResponseRef轉(zhuǎn)化為CFHTTPMessageRef
            CFHTTPMessageRef message = originURLResponseGetHTTPResponse(cfResponse);
            // 獲取http協(xié)議版本
            CFStringRef cfVersion = CFHTTPMessageCopyVersion(message);
            if (NULL != cfVersion) {
                version = (__bridge NSString *)cfVersion;
                CFRelease(cfVersion);
            }
            CFRelease(cfResponse);
        }
    }

    // 獲取失敗的話則設(shè)置一個默認(rèn)值
    if (nil == version || 0 == version.length) {
        version = @"HTTP/1.1";
    }

    return version;
}

@end

五膏燃、最后的話

  1. _CFURLResponse和CFURLResponseGetHTTPResponse都是蘋果沒有公開的,使用時需要特殊處理下何什,以防上架時被蘋果判定為使用了Private API而被拒组哩。至于怎么處理就不細(xì)說了,可以采用拼接字符串或者對其進(jìn)行加解密的方式处渣。
  2. 之前做HTTP2的時候伶贰,不知道在客戶端要怎樣獲取請求使用的HTTP協(xié)議版本,以判斷是否協(xié)商使用了HTTP2協(xié)議罐栈,都是通過在服務(wù)端查看日志來判斷的∈蜓茫現(xiàn)在好了,直接通過NSURLResponse就可以獲取到了荠诬。
  3. 說來慚愧琅翻,工作多年了還是頭一回寫博客。哪里寫得不好或者有什么錯誤柑贞,還請大家多多包涵并給予指正方椎。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市钧嘶,隨后出現(xiàn)的幾起案子棠众,更是在濱河造成了極大的恐慌,老刑警劉巖有决,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闸拿,死亡現(xiàn)場離奇詭異,居然都是意外死亡书幕,警方通過查閱死者的電腦和手機(jī)新荤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來台汇,“玉大人苛骨,你說我怎么就攤上這事±撸” “怎么了智袭?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵奔缠,是天一觀的道長掠抬。 經(jīng)常有香客問我,道長校哎,這世上最難降的妖魔是什么两波? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任瞳步,我火速辦了婚禮,結(jié)果婚禮上腰奋,老公的妹妹穿的比我還像新娘单起。我一直安慰自己,他們只是感情好劣坊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布嘀倒。 她就那樣靜靜地躺著,像睡著了一般局冰。 火紅的嫁衣襯著肌膚如雪测蘑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天康二,我揣著相機(jī)與錄音碳胳,去河邊找鬼。 笑死沫勿,一個胖子當(dāng)著我的面吹牛挨约,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播产雹,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼诫惭,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蔓挖?” 一聲冷哼從身側(cè)響起贝攒,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎时甚,沒想到半個月后隘弊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡荒适,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年梨熙,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刀诬。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡咽扇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出陕壹,到底是詐尸還是另有隱情质欲,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布糠馆,位于F島的核電站嘶伟,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏又碌。R本人自食惡果不足惜九昧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一绊袋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧铸鹰,春花似錦癌别、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至剖毯,卻和暖如春诞仓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背速兔。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工墅拭, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人涣狗。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓谍婉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親镀钓。 傳聞我的和親對象是個殘疾皇子穗熬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

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

  • iOS網(wǎng)絡(luò)編程讀書筆記 Facade Tester客戶端門面模式的實(shí)例(被動版本化) 被動版本化,所以硬編碼URL...
    melouverrr閱讀 1,606評論 3 7
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理丁溅,服務(wù)發(fā)現(xiàn)唤蔗,斷路器,智...
    卡卡羅2017閱讀 134,659評論 18 139
  • 轉(zhuǎn)載于:http://mrpeak.cn/blog/http2/ HTTP 2.0的那些事 在我們所處的互聯(lián)網(wǎng)世界...
    柒黍閱讀 2,363評論 0 8
  • 218.241.181.202 wxhl60 123456 192.168.10.253 wxhl66 wxhl6...
    CYC666閱讀 1,387評論 0 6
  • 間諜同盟 導(dǎo)演: 羅伯特·澤米吉斯 編劇: 斯蒂文·奈特 主演: 布拉德·皮特 / 瑪麗昂·歌迪亞 / 馬修·古迪...
    胡禿閱讀 452評論 0 50