本文是逐行翻譯,便于參照原文,如有歧義或者疑問請(qǐng)閱讀原文比較潘酗。
于 2017.1.25
================================
1.1
CustomHTTPProtocol shows how to use an NSURLProtocol subclass to intercept the HTTP/HTTPS requests made by a high-level subsystem that does not otherwise expose its network connections. In this specific case, it intercepts the requests made by a UIWebView in order to support custom server trust evaluation. You can use this technique to solve various problems, including:
CustomHTTPProtocol為我們展示了怎樣利用NSURLProtocol子類來攔截更高層子系統(tǒng)中未暴露的網(wǎng)絡(luò)請(qǐng)求連接的HTTP/HTTPs請(qǐng)求杆兵。在這個(gè)特定的小范例中,為了幫助用戶服務(wù)器驗(yàn)證仔夺,CustomHTTPProtocol攔截了UIWebview中的網(wǎng)絡(luò)請(qǐng)求琐脏。你能用這項(xiàng)技術(shù)解決如下問題
o implementing custom HTTPS server trust evaluation in a UIWebView (perhaps to access a server with a self-signed certificate), as shown by this specific sample code
在UIWebView中實(shí)現(xiàn)自定義HTTPS服務(wù)器信任評(píng)估(可能訪問具有自簽名證書的服務(wù)器),如此特定示例代碼所示
o allowing HTTPS client identity choice in a UIWebView
在UIWebView中允許HTTPS客戶端標(biāo)識(shí)選擇
o supporting HTTP (RFC 2617) authentication in a UIWebView
在UIWebView中支持HTTP(RFC 2617)認(rèn)證
o debugging problems with any subsystem that uses NSURL{Session,Connection}, especially in situations where it uses HTTPS, and thus is not amenable(經(jīng)得起檢驗(yàn)的缸兔,易控制的) to packet tracing
調(diào)試任何使用NSURL {Session日裙,Connection}的子系統(tǒng),特別是在使用HTTPS的情況下惰蜜,因此不適合包跟蹤
Additionally, the core technique shown by this sample (an NSURLProtocol subclass) can be used to solve other problems including:
此外昂拂,此示例(NSURLProtocol子類)展示的核心技術(shù)也可用于解決其他問題,包括:
o forcing UIWebView to run through a custom proxy (easy to set up in the NSURLSession used for the recursive requests)
讓UIWView運(yùn)行在自定義的代理中(在NSURLSession中更容易設(shè)置遞歸請(qǐng)求)
o running HTTP requests over some non-standard transport scheme (HTTP over an External Accessory stream pair, for example)
通過某些非標(biāo)準(zhǔn)傳輸方案(例如通過EAAccessory傳輸?shù)腍TTP請(qǐng)求)運(yùn)行HTTP請(qǐng)求 注: External Accessory Framework是提供了配件連接iOS設(shè)備的通道抛猖。開發(fā)者可以通過它來開發(fā)連接配件的app格侯。
o supporting custom URL schemes for HTTP Live Streaming encryption keys
支持HTTP Live Streaming加密密鑰的自定義URL方案
CustomHTTPProtocol requires iOS 7 or later, although the NSURLProtocol subclass technique should work on any version of iOS and, for that matter, on Mac OS X 10.5 and later.
CustomHTTPProtocol需要iOS 7或更高版本,但是NSURLProtocol子類技術(shù)應(yīng)該可以在任何版本的iOS上運(yùn)行樟结,在Mac OS X 10.5及更高版本上也是如此瓢宦。
IMPORTANT: Before using the technique shown by this sample, review the "Compatibility Notes" section, below.
重要信息:在使用此示例所示的技術(shù)之前,請(qǐng)查看下面的“兼容性說明”部分鱼辙。
Packing List
The sample includes three top-level items:
該示例包括三個(gè)頂級(jí)項(xiàng)目:
o Read Me About CustomHTTPProtocol.txt -- This document.
o Read Me關(guān)于CustomHTTPProtocol.txt - 本文檔。
o CustomHTTPProtocol.xcodeproj -- An Xcode project for the sample.
o CustomHTTPProtocol.xcodeproj - 樣本的Xcode項(xiàng)目恐似。
o CustomHTTPProtocol -- A directory containing all the other stuff.
o CustomHTTPProtocol - 包含所有其他內(nèi)容的目錄葛闷。
Within the "CustomHTTPProtocol" directory you will find:
在“CustomHTTPProtocol”目錄中业踢,您將找到:
o Info.plist, main.m, Main.storyboard, Icons, Default Images -- Standard things you might find in any iOS app.
Info.plist稿湿,main.m延蟹,Main.storyboard稚照,Icons,Default Images - 您可以在任何iOS應(yīng)用程序中找到的標(biāo)準(zhǔn)內(nèi)容上枕。
o AppDelegate.{h,m} -- The application delegate class; this is a normal app delegate with some minor additions to a) enable the NSURLProtocol subclass, b) support logging from that subclass, and c) actually do the custom server trust evaluation (via a delegate callback from the NSURLProtocol subclass).
o AppDelegate棋恼。{h爪飘,m} - 應(yīng)用程序委托類; 這是一個(gè)普通的應(yīng)用程序代理师崎,有一些小的g改動(dòng) a)啟用NSURLProtocol子類犁罩,b)支持從該子類的日志記錄床估,和c)做自定義服務(wù)器評(píng)估(通過從NSURLProtocol子類的委托回調(diào))。
o ThreadInfo.{h,m} -- A helper class used by the app delegate logging code.
o ThreadInfo递胧。{h谓着,m} - 由應(yīng)用程序委托日志記錄代碼使用的助手類赊锚。
o WebViewController.{h,m} -- The main view controller, which runs a web view and manages the process of downloading anchor certificates.
主視圖控制器耸袜,它運(yùn)行Web視圖并管理下載錨點(diǎn)證書的過程堤框。
o WebViewControllerHTML -- Some HTML files used by the above.
o WebViewControllerHTML - 上面代碼需要使用的一些HTML文件蜈抓。
o CredentialsManager.{h,m} -- A singleton model object that maintains the list of trusted anchors for the app.
o CredentialsManager沟使。{h腊嗡,m} - 一個(gè)單例模型對(duì)象燕少,維護(hù)應(yīng)用程序的可信錨的列表。
o Core Code -- The code that actually implements the NSURLProtocol subclass. Within this directory you'll find four modules:
o核心代碼 - 實(shí)際實(shí)現(xiàn)NSURLProtocol子類的代碼镶摘。在此目錄中凄敢,您將找到四個(gè)模塊:
CustomHTTPProtocol.{h,m} -- The actual NSURLProtocol subclass.
CustomHTTPProtocol涝缝。{h,m} - 實(shí)際的NSURLProtocol子類滩援。QNSURLSessionDemux.{h,m} -- A helper class used by instances of the CustomHTTPProtocol class to demultiplex NSURLSession delegate events.
QNSURLSessionDemux玩徊。{h泣棋,m} - 由CustomHTTPProtocol類的實(shí)例用于解構(gòu)NSURLSession委托事件的輔助類。CanonicalRequest.{h,m} -- A module that contains a single function, CanonicalRequestForRequest, which implements some standard functionality. See the "Caveats" section (below) for more information about this.
CanonicalRequest澈吨。{h技竟,m} - 包含單個(gè)函數(shù)CanonicalRequestForRequest的模塊,它實(shí)現(xiàn)了一些標(biāo)準(zhǔn)功能联逻。有關(guān)詳細(xì)信息包归,請(qǐng)參閱“注意事項(xiàng)”部分(如下)公壤。CacheStoragePolicy.{h,m} -- A module that contains a single function, CacheStoragePolicyForRequestAndResponse, which implements some standard functionality. See the "Compatibility Notes" section (below) for more information about this.
CacheStoragePolicy。{h确憨,m} - 包含單個(gè)函數(shù)CacheStoragePolicyForRequestAndResponse的模塊休弃,它實(shí)現(xiàn)了一些標(biāo)準(zhǔn)功能。有關(guān)詳細(xì)信息丈甸,請(qǐng)參閱“兼容性注釋”部分(如下)医增。
Using the Sample使用范例代碼
To use the sample, simply run it on a device or the simulator. It will put up a web view that allows you to pick a number of sites to visit. To run a basic test, do the following:
要使用示例,只需在設(shè)備或模擬器上運(yùn)行它老虫。它會(huì)展示一個(gè)網(wǎng)絡(luò)視圖叶骨,允許你選擇一些網(wǎng)站進(jìn)行訪問。要運(yùn)行基本測試祈匙,請(qǐng)執(zhí)行以下操作:
\1. tap on the "CAcert (HTTPS)" link; you will see an error because the system does not trust the CAcert anchor by default
1.點(diǎn)擊“CAcert(HTTPS)”鏈接; 您將看到錯(cuò)誤忽刽,因?yàn)橄到y(tǒng)默認(rèn)不信任CAcert錨點(diǎn)
\2. tap the Sites button to get you back to the top
2.點(diǎn)擊網(wǎng)站按鈕,回到頂部
\3. tap the "Install CAcert Anchor" link, which takes you to the CAcert anchor install page
3.點(diǎn)擊“安裝CAcert錨點(diǎn)”鏈接夺欲,將鏈接轉(zhuǎn)到CAcert錨點(diǎn)安裝頁面
\4. tap the Install button; wait for the CAcert anchor to install
4.點(diǎn)擊安裝按鈕; 等待CAcert錨點(diǎn)安裝
Note: This affects only the CustomHTTPProtocol app, not the system as a whole.
注意:這僅影響CustomHTTPProtocol應(yīng)用程序,而不影響整個(gè)系統(tǒng)。
\5. tap the Sites button to take you back to the top again
5.點(diǎn)擊“站點(diǎn)”按鈕坷澡,將您帶回到頂端
\6. tap the "CAcert (HTTPS)" link; this time the site will be displayed because the UIWebView in this app now trusts the CAcert anchor
6.點(diǎn)擊“CAcert(HTTPS)”鏈接; 此時(shí)將顯示網(wǎng)站着降,因?yàn)榇藨?yīng)用程序中的UIWebView現(xiàn)在信任CAcert錨點(diǎn)
IMPORTANT: The app does not remember your installed anchors from launch to launch. See the "Caveats" section (below) for an explanation.
重要信息:該應(yīng)用程序不記得您從安裝啟動(dòng)到安裝的錨點(diǎn)侈咕。有關(guān)說明罐柳,請(qǐng)參閱“注意事項(xiàng)”部分(如下)肮蛹。
Building the Sample構(gòu)建范例代碼
The sample was built using Xcode 5.1.1 on OS X 10.9.4 using the iOS 7.1 SDK. You should be able to just open the project and choose Run from the Product menu.
該示例是使用Xcode 5.1.1在OS X 10.9.4使用iOS 7.1 SDK構(gòu)建的。您應(yīng)該只能打開項(xiàng)目并從產(chǎn)品菜單中選擇運(yùn)行
Compatibility Notes兼容性說明
This sample assumes that UIWebView uses NSURLConnection in a way that allows the NSURLProtocol subclass to affect its usage. This is currently true, but there's no guarantee that it will be true forever. Certainly, there are existing subsystems within iOS where this is not the case (for example, the movie playback subsystem).
此示例假設(shè)UIWebView使用NSURLConnection以允許NSURLProtocol子類能夠在UIWebView上生效。現(xiàn)在這是真實(shí)有效的萌壳,但不能保證它將永遠(yuǎn)是真實(shí)有效的尺借。當(dāng)然栅表,在iOS中存在不是這種情況的子系統(tǒng)(例如找岖,電影回放子系統(tǒng))。
WARNING: If you use an NSURLProtocol subclass to customize UIWebView's behaviour, you should file a bug that describes your requirements and requests that appropriate customization points be provided via the UIWebView delegate.
警告:如果使用NSURLProtocol子類來定制UIWebView的行為落竹,您應(yīng)該提交一個(gè)描述您的需求的錯(cuò)誤藤为,并請(qǐng)求通過UIWebView代理提供適當(dāng)?shù)淖远x點(diǎn)。
https://developer.apple.com/bugreporter/
Likewise, if you use this technique for other subsystems within iOS, you should file a bug requesting that those subsystems be enhanced to support the customization points that you require.
同樣坞笙,如果您對(duì)iOS中的其他子系統(tǒng)使用此技術(shù)硕糊,您應(yīng)該提交一個(gè)錯(cuò)誤檬某,要求改造這些子系統(tǒng)以支持您需要的自定義點(diǎn)
If you plan to use a custom NSURLProtocol subclass for movie playback, watch WWDC 2011 Session 408 "HTTP Live Streaming Update" for important information about how NSURLProtocol subclasses interact with the media subsystem.
如果計(jì)劃使用自定義NSURLProtocol子類進(jìn)行電影播放,請(qǐng)觀看WWDC 2011會(huì)話408“HTTP實(shí)時(shí)流更新”,了解有關(guān)NSURLProtocol子類與媒體子系統(tǒng)如何交互的重要信息。
https://developer.apple.com/videos/wwdc/2011/
Be aware that, if a subsystem uses NSURLSession, your custom NSURLProtocol subclass will only see requests issued in the shared session (+[NSURLSession sharedSession]). For the protocol to work in other sessions, it must be listed (via the NSURLSessionConfiguration.protocolClasses property) in the configuration used to create the session.
請(qǐng)注意青责,如果子系統(tǒng)使用NSURLSession脖隶,您的自定義NSURLProtocol子類將只看到在共享會(huì)話(+ [NSURLSession sharedSession])中發(fā)出的請(qǐng)求悔据。要使協(xié)議在其他會(huì)話中工作缀蹄,必須在用于創(chuàng)建會(huì)話的配置中列出(通過NSURLSessionConfiguration.protocolClasses屬性)。
An NSURLProtocol subclass can potentially affect any piece of code in your process that uses NSURL{Session,Connection} and, as such, represents a real compatibility risk. To minimize the potential for problems:
NSURLProtocol子類可能會(huì)影響進(jìn)程中使用NSURL {Session奶躯,Connection}的任何代碼段帚桩,因此代表了真正的兼容性風(fēng)險(xiǎn)。為了盡量減少潛在的問題:
o limit your scope -- The easiest way to prevent problems is to limit the type of URLs that you handle. To do this, implement +canInitWithRequest: so that it declines to process everything except the specific requests you're interested in. For example, while +canInitWithRequest: in this sample accepts both HTTP and HTTPS requests, it would be sufficient to have it accept only HTTPS requests, allowing HTTP requests to be processed by the default protocol implementation.
o限制您的范圍 - 防止問題的最簡單方法是限制您處理的URL類型嘹黔。為了做到這一點(diǎn)账嚎,實(shí)現(xiàn)+ canInitWithRequest:以便它拒絕處理除了你感興趣的特定請(qǐng)求之外的任何東西。例如参淹,while + canInitWithRequest:在這個(gè)示例接受HTTP和HTTPS請(qǐng)求醉锄,它就足以讓它接受只有HTTPS請(qǐng)求,允許HTTP請(qǐng)求由默認(rèn)協(xié)議實(shí)現(xiàn)處理浙值。
o memory -- Be careful not to use too much memory, particularly on iOS.
o內(nèi)存 - 小心不要使用太多內(nèi)存恳不,特別是在iOS上。
o threading -- Be sure to follow the threading rules described below.
o線程 - 請(qǐng)務(wù)必遵循下面描述的線程規(guī)則开呐。
It's not possible to accurately implement an HTTP/HTTPS NSURLProtocol subclass without reimplementing some system functionality. Any time you reimplement system functionality you run the risk that the system functionality might change, leaving your reimplemention behind. There are two major areas of concern here:
不可能在不重新實(shí)現(xiàn)某些系統(tǒng)功能的情況下準(zhǔn)確實(shí)現(xiàn)HTTP / HTTPS NSURLProtocol子類烟勋。每當(dāng)您重新實(shí)現(xiàn)系統(tǒng)功能時(shí),您都會(huì)遇到系統(tǒng)功能可能會(huì)改變的風(fēng)險(xiǎn)筐付,因此您可以重新實(shí)現(xiàn)系統(tǒng)功能卵惦。這里有兩個(gè)主要關(guān)注的領(lǐng)域:
o URL canonicalization -- The code in the CanonicalRequestForRequest function is complex, and there's certainly some scope for future compatibility problems.
o URL規(guī)范化 - CanonicalRequestForRequest函數(shù)中的代碼很復(fù)雜,并且對(duì)于未來的兼容性問題肯定有一定范圍瓦戚。
o cache storage policy -- The code in the CacheStoragePolicyForRequestAndResponse function isn't nearly as complex as the URL canonicalization code, but it is another example of reimplementing system functionality.
o緩存存儲(chǔ)策略 - CacheStoragePolicyForRequestAndResponse函數(shù)中的代碼不像URL規(guī)范化代碼那么復(fù)雜沮尿,但它是重新實(shí)現(xiàn)系統(tǒng)功能的另一個(gè)示例
Threading Notes線程注釋
NSURLProtocol subclasses are tricky to implement correctly. The most important issues relate to threading. The methods that an NSURLProtocol subclass is expected to implement can be split into two groups:
NSURLProtocol子類很難正確實(shí)現(xiàn)。最重要的問題與線程有關(guān)较解。NSURLProtocol子類期望實(shí)現(xiàn)的方法可以分為兩組:
o any thread -- These methods may be called from any thread and must be completely thread safe:
o任何線程 - 這些方法可以從任何線程調(diào)用畜疾,并且必須完全線程安全:
-initWithRequest:cachedResponse:client:
-dealloc
+canInitWithRequest:
+canonicalRequestForRequest:
+requestIsCacheEquivalent:toRequest:
o client thread -- These methods are always called by the client thread:
o客戶端線程 - 這些方法總是由客戶端線程調(diào)用:
-startLoading
-stopLoading
The exact identity of the client thread is unspecified, but you can be assured that:
客戶端線程的確切標(biāo)識(shí)未指定,但您可以放心:
o -startLoading is called by the client thread
o -startLoading由客戶端線程調(diào)用
o -stopLoading will be called by that same client thread
o -stopLoading將由相同的客戶端線程調(diào)用
o -stopLoading will be called before -dealloc is called
o -stopLoading將在調(diào)用-dealloc之前調(diào)用
o the client thread will run its run loop
o客戶端線程將運(yùn)行其運(yùn)行循環(huán)
In addition, an NSURLProtocol subclass is expected to call the various methods of the NSURLProtocolClient protocol from the client thread, including all of the following:
此外印衔,NSURLProtocol子類期望從客戶端線程調(diào)用NSURLProtocolClient協(xié)議的各種方法啡捶,包括以下所有方法:
-URLProtocol:wasRedirectedToRequest:redirectResponse:
-URLProtocol:didReceiveResponse:cacheStoragePolicy:
-URLProtocol:didLoadData:
-URLProtocolDidFinishLoading:
-URLProtocol:didFailWithError:
-URLProtocol:didReceiveAuthenticationChallenge:
-URLProtocol:didCancelAuthenticationChallenge:
The NSURLProtocol subclass must call the client callbacks in the expected order. This breaks down into three phases:
NSURLProtocol子類必須以預(yù)期的順序調(diào)用客戶端回調(diào)。這分為三個(gè)階段:
\1. pre-response -- In the initial phase the NSURLProtocol can make any number of -URLProtocol:wasRedirectedToRequest:redirectResponse: and -URLProtocol:didReceiveAuthenticationChallenge: callbacks.
1.預(yù)響應(yīng) - 在初始化階段奸焙,NSURLProtocol可以創(chuàng)建任意數(shù)量的-URLProtocol:wasRedirectedToRequest:redirectResponse:和-URLProtocol:didReceiveAuthenticationChallenge:callbacks瞎暑。
\2. response -- It must then call -URLProtocol:didReceiveResponse:cacheStoragePolicy: to indicate the arrival of a definitive response.
\2. 響應(yīng) - 然后它必須調(diào)用-URLProtocol:didReceiveResponse:cacheStoragePolicy:來指示確定響應(yīng)的到達(dá)彤敛。
\3. post-response -- After receiving a response it may then make any number of -URLProtocol:didLoadData: callbacks, followed by a -URLProtocolDidFinishLoading: callback.
\3. 收到響應(yīng)后 - 在接收到響應(yīng)之后,它可以使用任意數(shù)量的-URLProtocol:didLoadData:callbacks了赌,隨后是一個(gè)-URLProtocolDidFinishLoading:回調(diào)墨榄。
The -URLProtocol:didFailWithError: callback can be made at any time (although keep in mind the following point).
-URLProtocol:didFailWithError:可以隨時(shí)進(jìn)行回調(diào)(但請(qǐng)記住以下幾點(diǎn))。
The NSURLProtocol subclass must only send one authentication challenge to the client at a time. After calling -URLProtocol:didReceiveAuthenticationChallenge:, it must wait for the client to resolve the challenge before calling any callbacks other than -URLProtocol:didCancelAuthenticationChallenge:. This means that, if the connection fails while there is an outstanding authentication challenge, the NSURLProtocol subclass must call -URLProtocol:didCancelAuthenticationChallenge: before calling -URLProtocol:didFailWithError:.
NSURLProtocol子類只能一次向客戶端發(fā)送一個(gè)身份驗(yàn)證質(zhì)詢揍拆。調(diào)用-URLProtocol:didReceiveAuthenticationChallenge:后渠概,它必須等待客戶端解決挑戰(zhàn),然后再調(diào)用任何回調(diào)之外的-URLProtocol:didCancelAuthenticationChallenge:嫂拴。這意味著播揪,如果連接失敗,而有一個(gè)未完成的身份驗(yàn)證質(zhì)詢筒狠,NSURLProtocol子類必須調(diào)用-URLProtocol:didCancelAuthenticationChallenge:之前調(diào)用-URLProtocol:didFailWithError :.
WARNING: An NSURLProtocol subclass must operate asynchronously. It is not safe for it to block the client thread for extended periods of time. For example, while it's reasonable for an NSURLProtocol subclass to defer work (like an authentication challenge) to the main thread, it must do so asynchronously. If the NSURLProtocol subclass passes a task to the main thread and then blocks waiting for the result, it's likely to deadlock the application.
警告:NSURLProtocol子類必須異步操作猪狈。它不能安全地阻止客戶端線程很長一段時(shí)間。例如辩恼,雖然NSURLProtocol子類推遲到主線程的工作(如身份驗(yàn)證質(zhì)詢)是合理的雇庙,但它必須異步執(zhí)行。如果NSURLProtocol子類將任務(wù)傳遞給主線程灶伊,然后阻塞等待結(jié)果疆前,它可能會(huì)死鎖應(yīng)用程序。
Caveats 附加說明
The sample app does not remember your installed anchors from launch to launch. This would be easy to implement by extending the CredentialsManager class to store the anchors, but I chose not to do this in order to keep things simple.
示例應(yīng)用程序不會(huì)記住從啟動(dòng)到啟動(dòng)安裝的錨點(diǎn)聘萨。這將很容易實(shí)現(xiàn)通過擴(kuò)展CredentialsManager類來存儲(chǔ)錨點(diǎn)竹椒,但我選擇不這樣做,以保持簡單米辐。
The NSURLProtocolClient protocol has not been extended to support advanced protection spaces rdar://problem/9226151. This means there's no way for your NSURLProtocol subclass to call the NSURLConnection delegate's -connection:canAuthenticateAgainstProtectionSpace: method. If you do send authentication challenges to your client, you must only send standard authentication challenges (that is, challenges whose protection space's authentication method is NSURLAuthenticationMethodDefault, NSURLAuthenticationMethodHTTPBasic, or NSURLAuthenticationMethodHTTPDigest). You must process other authentication challenges yourself (which is often the reason why you implemented the custom NSURLProtocol subclass in the first place).
NSURLProtocolClient協(xié)議尚未擴(kuò)展胸完,以支持高級(jí)保護(hù)空間<rdar:// problem / 9226151>。這意味著您的NSURLProtocol子類無法調(diào)用NSURLConnection委托的-connection:canAuthenticateAgainstProtectionSpace:方法翘贮。如果您向客戶端發(fā)送身份驗(yàn)證挑戰(zhàn)赊窥,則您必須只發(fā)送標(biāo)準(zhǔn)身份驗(yàn)證挑戰(zhàn)(即,保護(hù)空間的身份驗(yàn)證方法為NSURLAuthenticationMethodDefault狸页,NSURLAuthenticationMethodHTTPBasic或NSURLAuthenticationMethodHTTPDigest的挑戰(zhàn))锨能。您必須自己處理其他身份驗(yàn)證挑戰(zhàn)(這通常是您首先實(shí)現(xiàn)自定義NSURLProtocol子類的原因)。
Similarly, there is no way for your NSURLProtocol subclass to call the NSURLConnection delegate's -connection:needNewBodyStream: or -connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite: methods (rdar://problem/9226155 and rdar://problem/9226157). The latter is not a serious concern--it just means that your clients don't get upload progress--but the former is a real issue. If you're in a situation where you might need a second copy of a request body, you will need your own logic to make that copy, including the case where the body is a stream.
同樣芍耘,你的NSURLProtocol子類沒有辦法調(diào)用NSURLConnection委托的-connection:needNewBodyStream:或-connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:methods(<rdar:// problem / 9226155>和<rdar:// problem / 9226157 >)腹侣。后者不是一個(gè)嚴(yán)重的問題 - 這只是意味著你的客戶端不會(huì)獲得上傳進(jìn)度 - 但前者是一個(gè)真正的問題。如果您遇到需要請(qǐng)求正文的第二個(gè)副本的情況齿穗,您需要使用自己的邏輯來進(jìn)行該副本,包括正文是流的情況饺律。
And finally, there is no way for your NSURLProtocol subclass to call the NSURLConnection delegate's -connectionShouldUseCredentialStorage: or -connection:willCacheResponse: methods (rdar://problem/9226160). This shouldn't be a problem in most circumstances, but could cause problems for complex clients.
最后窃页,你的NSURLProtocol子類沒有辦法調(diào)用NSURLConnection委托的-connectionShouldUseCredentialStorage:或-connection:willCacheResponse:methods(<rdar:// problem / 9226160>)跺株。這在大多數(shù)情況下不應(yīng)該是問題,但可能對(duì)復(fù)雜的客戶端造成問題脖卖。
Creating an NSHTTPURLResponse from scratch is tricky. This sample gets around the issue by calling NSURLConnection recursively, which causes the system to create the NSHTTPURLResponse on its behalf. If you need to do something different, see the "Creating an NSHTTPURLResponse" section below.
從頭開始創(chuàng)建NSHTTPURLResponse是棘手的乒省。此示例通過遞歸調(diào)用NSURLConnection來解決問題,這導(dǎo)致系統(tǒng)代表它創(chuàng)建NSHTTPURLResponse畦木。如果您需要執(zhí)行不同的操作袖扛,請(qǐng)參閱下面的“創(chuàng)建NSHTTPURLResponse”部分。
Using a custom NSURLProtocol subclass can cause CFNetwork to leak on HTTP redirects rdar://problem/10093777. To reduce the impact of this leak, minimize the size of your NSURLProtocol subclass object and have it clean up its resources in -stopLoading rather than in -dealloc.
使用自定義NSURLProtocol子類可能導(dǎo)致CFNetwork在HTTP重定向<rdar:// problem / 10093777>上泄漏十籍。為了減少此泄漏的影響蛆封,最小化NSURLProtocol子類對(duì)象的大小,并在-stopLoading中而不是在-dealloc中清除其資源勾栗。
The CanonicalRequest code would most definitely benefit from adopting the NSURLComponents class that was added in iOS 7 and OS X 10.9. The technique it currently uses is less than ideal rdar://problem/17383757.
CanonicalRequest代碼最有利于采用在iOS 7和OS X 10.9中添加的NSURLComponents類惨篱。它當(dāng)前使用的技術(shù)不太理想<rdar:// problem / 17383757>。
Creating an NSHTTPURLResponse 創(chuàng)建NSHTTPURLResponse
Prior to iOS 5 (and OS X 10.7) there was no supported way to construct a valid NSHTTPURLResponse from scratch rdar://problem/5817126. The sticking point was that the only public initialisation method (-initWithURL:MIMEType:expectedContentLength:textEncodingName:) did not let you specify the HTTP status code or headers. Moreover, because of the interactions between NSURLConnection and CFNetwork, you can't work around this limitation by subclassing NSHTTPURLResponse and overriding the -statusCode and -allHeaderFields methods; such overrides are not seen by all subsystems that use NSURLConnection (most notably UIWebView).
在iOS 5(和OS X 10.7)之前围俘,沒有支持的方法從頭構(gòu)建有效的NSHTTPURLResponse <rdar:// problem / 5817126>砸讳。關(guān)鍵點(diǎn)是,唯一的公共初始化方法(-initWithURL:MIMEType:expectedContentLength:textEncodingName :)不允許您指定HTTP狀態(tài)代碼或標(biāo)頭界牡。此外簿寂,由于NSURLConnection和CFNetwork之間的交互,您不能通過子類化NSHTTPURLResponse并覆蓋-statusCode和-allHeaderFields方法來解決此限制; 這樣的覆蓋不是所有使用NSURLConnection(最引人注目的UIWebView)的子系統(tǒng)宿亡。
If you only support iOS 5 or later, this isn't an issue: when you need to construct an NSHTTPURLResponse, simply use the newly introduced -initWithURL:statusCode:HTTPVersion:headerFields: initialisation method. However, if you must support older systems, things get more complex. There are a variety of less-than-ideal workarounds:
如果你只支持iOS 5或更高版本常遂,這不是一個(gè)問題:當(dāng)你需要構(gòu)造一個(gè)NSHTTPURLResponse,只需使用新引入的-initWithURL:statusCode:HTTPVersion:headerFields:initialisation方法她混。但是烈钞,如果您必須支持舊系統(tǒng),則事情變得更復(fù)雜坤按。有多種不太理想的解決方法:
o Actually pass the request off to the default HTTP or HTTPS implementation by calling NSURL{Session,Connection} recursively. This will give you back an NSHTTPURLResponse that you can pass up to your client.
o實(shí)際上通過遞歸調(diào)用NSURL {Session毯欣,Connection}將請(qǐng)求傳遞給默認(rèn)的HTTP或HTTPS實(shí)現(xiàn)。這將給你一個(gè)NSHTTPURLResponse臭脓,你可以傳遞給你的客戶端酗钞。
This is the approach shown by this sample.
這是此示例顯示的方法。
o An extension of this approach is to implement a small loopback web server that returns the HTTP response you need to generate the correct NSHTTPURLResponse.
o這種方法的擴(kuò)展是實(shí)現(xiàn)一個(gè)小的環(huán)回Web服務(wù)器来累,它返回生成正確的NSHTTPURLResponse所需的HTTP響應(yīng)砚作。
o NSHTTPURLResponse supports the NSCoding protocol. If your NSURLProtocol only needs to return a small number of fixed responses, you could create those responses via NSURL{Session,Connection} at build time, archive them, and then unarchive them at run time.
o NSHTTPURLResponse支持NSCoding協(xié)議。如果您的NSURLProtocol只需要返回少量的固定響應(yīng)嘹锁,您可以在構(gòu)建時(shí)通過NSURL {Session葫录,Connection}創(chuàng)建這些響應(yīng),將它們存檔领猾,然后在運(yùn)行時(shí)取消存檔米同。
Credits and Version History
If you find any problems with this sample, please file a bug against it.
https://developer.apple.com/bugreporter/
1.0d1..8 (2011..2013) shipped to a limited number of developers on a one-to-one basis.
1.0 (Aug 2013) was the first shipping version.
1.1 (Jul 2014) is an update that changes the protocol to use NSURLSession for its recursive requests. This works around a deadlock issue rdar://problem/17342579 and makes the code more future proof. There were also numerous other minor changes.
Share and Enjoy
Apple Developer Technical Support
Core OS/Hardware
28 Jul 2014