使用NSURLProtocol實現(xiàn)本地靜態(tài)文件的web服務(wù)器

需求前提:

最近公司有這樣一個需求,要用webView加載網(wǎng)頁游戲劣针,由于蘋果方面不支持webView通過url從服務(wù)器端加載游戲括眠,于是html,js等資源文件就放到了本地項目里面,通過webView加載html來實現(xiàn)交互痕鳍。
但是html/js文件里有指向http/https的請求停团,這樣webView就加載不出來本地資源了医男,因此我們需要攔截http網(wǎng)絡(luò)請求随闪,把這些url攔截到滑绒,然后構(gòu)建成我們可以響應(yīng)的方式闷堡。


攔截準(zhǔn)備:
假設(shè)我們本地服務(wù)器的端口為1000,服務(wù)器名為:localhost疑故,協(xié)議是http
那么需要攔截的URL為:http://localhost:1000


實現(xiàn)思路:
攔截URL有如下兩種方式:

  • 猜想1:webView自己的代理方法攔截URL
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;

嘗試攔截 https://www.baidu.com杠览, 此代理方法確實攔截到了這個url,但是攔截不到內(nèi)部圖片等具體資源的url纵势,因此猜想1失效踱阿。

webView攔截URL.png

  • 猜想2:NSURLProtocol攔截 ~ 可以攔截的網(wǎng)絡(luò)請求包括NSURLSession管钳,NSURLConnection以及UIWebVIew,(WKWebView需要特定的方式實現(xiàn)才能做到url被攔截软舌,后續(xù)補充)

嘗試攔截 https://www.baidu.com才漆, 此代理方法攔截到了所有資源的url,因此猜想2可行葫隙。

NSURLProtocol攔截URL.png

實現(xiàn)流程:
一、在想要攔截的地方先注冊:

[NSURLProtocol registerClass:[CustomURLProtocol class]];

不想攔截則取消注冊:

[NSURLProtocol unregisterClass:[CustomURLProtocol class]];

二躏仇、攔截網(wǎng)絡(luò)請求恋脚,NSURLProtocol會依次執(zhí)行下列方法:
1.該方法會拿到request的對象,我們可以通過該方法的返回值來篩選request是否需要被NSURLProtocol做攔截處理焰手。

+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
    NSString *monitorStr = request.URL.absoluteString;
//    NSLog(@"monitorStr=%@",monitorStr);
    
    // 只處理 http://localhost:1000/... 的請求
    if ( ([request.URL.absoluteString hasPrefix:@"http://localhost:1000”]))
    {
        //看看是否已經(jīng)處理過了糟描,防止無限循環(huán)
        if ([NSURLProtocol propertyForKey:URLProtocolHandledKey inRequest:request]) {
            return NO;
        }
        
        return YES;
    }
    return NO;
}
NSURLProtocol攔截資源地址.png

2.在該方法中,我們可以對request進行處理书妻。例如修改請求頭部信息等船响。最后返回一個處理后的request實例。例如我們攔截到 https://www.baidu.com躲履, 而通過修改request见间,將url指向http://www.reibang.com。 類似于webView代理方法攔截工猜,將其指向一個新的url米诉。如果不修改,則返回request本身篷帅。

+ (NSURLRequest *) canonicalRequestForRequest:(NSURLRequest *)request {
//    NSMutableURLRequest *mutableReqeust = [request mutableCopy];
//    mutableReqeust = [self redirectHostInRequset:mutableReqeust];
    return request;
}

3.在該方法中史侣,把(處理過的或者不需處理的)request重新發(fā)送出去。我們要做的就是修改響應(yīng)體response魏身,騙過服務(wù)器惊橱,按我們拼接響應(yīng)的方式去響應(yīng)。以下為拼接響應(yīng)體代碼箭昵。

- (void)startLoading
{
    //1.獲取資源文件路徑 ajkyq/index.html
    NSURL *url = [self request].URL;
    NSString *resourcePath = url.path;
    resourcePath = [resourcePath substringFromIndex:1];//把第一個/去掉
    
    //2.讀取資源文件內(nèi)容
    NSString *path = [[NSBundle mainBundle] pathForResource:resourcePath ofType:nil];
    NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path];
    NSData *data = [file readDataToEndOfFile];
    [file closeFile];
    
    //3.拼接響應(yīng)Response
    NSInteger dataLength = data.length;
    NSString *mimeType = [self getMIMETypeWithCAPIAtFilePath:path];
    NSString *httpVersion = @"HTTP/1.1";
    NSHTTPURLResponse *response = nil;
    
    if (dataLength > 0) {
        response = [self jointResponseWithData:data dataLength:dataLength mimeType:mimeType requestUrl:url statusCode:200 httpVersion:httpVersion];
    } else {
        response = [self jointResponseWithData:[@"404" dataUsingEncoding:NSUTF8StringEncoding] dataLength:3 mimeType:mimeType requestUrl:url statusCode:404 httpVersion:httpVersion];
    }
    
    //4.響應(yīng)
    [[self client] URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
    [[self client] URLProtocol:self didLoadData:data];
    [[self client] URLProtocolDidFinishLoading:self];
}
 
#pragma mark - 拼接響應(yīng)Response
-(NSHTTPURLResponse *)jointResponseWithData:(NSData *)data dataLength:(NSInteger)dataLength mimeType:(NSString *)mimeType requestUrl:(NSURL *)requestUrl statusCode:(NSInteger)statusCode httpVersion:(NSString *)httpVersion
{
    NSDictionary *dict = @{@"Content-type":mimeType,
                           @"Content-length":[NSString stringWithFormat:@"%ld",dataLength]};
    NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:requestUrl statusCode:statusCode HTTPVersion:httpVersion headerFields:dict];
    return response;
}

備注:以上為NSURLProtocol實現(xiàn)攔截URL的流程税朴,目前只適用于UIWebView,至于WKWebView攔截URL的實現(xiàn)方式后續(xù)會補充(蘋果做了一些操作家制,導(dǎo)致用不能用以上方式攔截WKWebView的URL)掉房。我列舉了幾篇文章,思路是相通的慰丛。我會盡快把我寫的demo上傳到github卓囚,和大家分享。

1.http://www.reibang.com/p/02781c0bbca9 NSURLProtocol全攻略
2.https://github.com/liujinlongxa/NSURLProtocolDemo/blob/master/NSURLProtocolDemo/MySessionURLProtocol.m NSURLProtocolDemo
3.https://github.com/rnapier/RNCachingURLProtocol/blob/master/RNCachingURLProtocol.m 基于緩存的NSURLProtocol
4.https://github.com/yeatse/NSURLProtocol-WebKitSupport 基于WKWebKit的NSURLProtocol攔截
5.http://www.cnblogs.com/goodboy-heyang/p/5193741.html iOS開發(fā)之網(wǎng)絡(luò)編程--獲取文件的MIMEType

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末诅病,一起剝皮案震驚了整個濱河市哪亿,隨后出現(xiàn)的幾起案子粥烁,更是在濱河造成了極大的恐慌,老刑警劉巖蝇棉,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件讨阻,死亡現(xiàn)場離奇詭異,居然都是意外死亡篡殷,警方通過查閱死者的電腦和手機钝吮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來板辽,“玉大人奇瘦,你說我怎么就攤上這事【⑾遥” “怎么了耳标?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長邑跪。 經(jīng)常有香客問我次坡,道長,這世上最難降的妖魔是什么画畅? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任砸琅,我火速辦了婚禮,結(jié)果婚禮上轴踱,老公的妹妹穿的比我還像新娘明棍。我一直安慰自己,他們只是感情好寇僧,可當(dāng)我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布摊腋。 她就那樣靜靜地躺著,像睡著了一般嘁傀。 火紅的嫁衣襯著肌膚如雪兴蒸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天细办,我揣著相機與錄音橙凳,去河邊找鬼。 笑死笑撞,一個胖子當(dāng)著我的面吹牛岛啸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播茴肥,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼坚踩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了瓤狐?” 一聲冷哼從身側(cè)響起瞬铸,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤批幌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后嗓节,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荧缘,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年拦宣,在試婚紗的時候發(fā)現(xiàn)自己被綠了截粗。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鸵隧,死狀恐怖绸罗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情掰派,我是刑警寧澤从诲,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布左痢,位于F島的核電站靡羡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏俊性。R本人自食惡果不足惜略步,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望定页。 院中可真熱鬧趟薄,春花似錦、人聲如沸典徊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卒落。三九已至羡铲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間儡毕,已是汗流浹背也切。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留腰湾,地道東北人雷恃。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像费坊,于是被迫代替她去往敵國和親倒槐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,665評論 2 354

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