UIWebView加載時添加請求頭(含NSURLProtocol方法)

前言

最近app需要重新整理webview加載的架構(gòu),把webview的請求方式由post改為get漱抓,而之前加載時傳參是通過post的請求體實現(xiàn)度苔,而現(xiàn)在需要將參數(shù)通過請求頭傳遞间狂,而且保證每次加載都要在請求頭加參惨奕。

過程

想要在請求頭加參其實很簡單揖赴,只要通過以下代碼:

[request addValue:"head" forHTTPHeaderField:@"key"];

現(xiàn)在主要問題是要在每次加載都在請求頭加參馆匿,于是我在網(wǎng)上搜到這篇文章 UIWebView 設置請求頭,基本上可以解決我的需求燥滑。下面分析以下代碼:

func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
      //先判斷是否含有請求頭渐北,打破死循環(huán)
      let dic:Dictionary<String,AnyObject> = request.allHTTPHeaderFields!
      let token = dic["UserToken"]
      if (token != nil) {
          return true
      }
      dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { () -> Void in
        dispatch_async(dispatch_get_main_queue(), { () -> Void in
          let newUrl = request.URL
          let newRequest:NSMutableURLRequest = NSMutableURLRequest.init(URL: newUrl!)
          newRequest.addValue(LoginInfoModel.sharedInstance.m_auth, forHTTPHeaderField: "UserToken")
          self.webView.loadRequest(newRequest)
          
        })
      }
      return false
}

如上,在uiwebview的代理方法webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) 中攔截網(wǎng)絡請求铭拧,先檢驗請求中是否含有參數(shù)赃蛛,有參數(shù)即直接通過(這一步十分關鍵,因為攔截的請求如沒有參數(shù)搀菩,會先在請求頭添加參數(shù)呕臂,再讓web view重新loadRequest,并且在代理方法中要返回NO肪跋,loadRequest會重新走這個代理方法歧蒋,如果沒有以上檢測通過return YES的話,就會陷入死循環(huán)州既,)谜洽。另外,之所以要在主線程中操作吴叶,我覺得是與webview的底層加載有關阐虚,webview加載時應該是開了子線程,所以重新加載要在主線程操作蚌卤,保證線程安全敌呈。至于文章中提及這種做法進入有iFrame的的頁面會有bug,由于我們后臺頁面沒有iFrame造寝,因此忽略掉磕洪。
另外還搜到另一種做法 NSURLProtocol學習筆記-UIWebView 設置請求頭,這種做法聽說更加完美地避免bug诫龙,我需要再驗證下析显,后續(xù)再更新......

通過NSURLProtocol修改請求頭

如上,網(wǎng)上搜到另外一種被推薦的做法签赃,利用NSURLProtocol修改請求頭谷异。可以先通過這篇文章 大致了解NSURLProtocol,實際操作時可參考這兩篇(锦聊,)歹嘹。以上兩篇文章在攔截請求后分別用NSURLConnection和NSURLSession,但由于NSURLConnection在iOS9中已經(jīng)停用孔庭,所以我參考的是第二篇文章尺上,以下對代碼進行分析材蛛。
首先如上面的文章所說,NSURLProtocol是一個抽象類怎抛,不能直接使用卑吭,需要子類化使用。建一個繼承自NSURLProtocol的子類

import UIKit

class MyURLProtocol: NSURLProtocol ,NSURLSessionDataDelegate {
  
  
  var session : NSURLSession?
  
  //判斷是否攔截
  override class func canInitWithRequest(request: NSURLRequest) -> Bool {
    
    return true

  }
  
  //修改攔截的請求
  override class func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest{
    let newRequest : NSMutableURLRequest = request.mutableCopy() as! NSMutableURLRequest
    
    newRequest.addValue("111", forHTTPHeaderField: "ttt")

    return newRequest;
    
  }
  //執(zhí)行特定的request請求
  override func startLoading() {
    let request = self.request.mutableCopy()
    NSURLProtocol.setProperty((true), forKey: "SessionProtocolKey", inRequest: request as! NSMutableURLRequest)
    
    let config : NSURLSessionConfiguration = NSURLSessionConfiguration.defaultSessionConfiguration()
    self.session = NSURLSession.init(configuration: config, delegate: self, delegateQueue: NSOperationQueue.mainQueue())
    let task : NSURLSessionDataTask = self.session!.dataTaskWithRequest(request as! NSURLRequest)
    task.resume()
    
  }
  //取消特定的request請求
  override func stopLoading() {
    
    self.session!.invalidateAndCancel()
    self.session = nil
    
    
  }
  
  //MARK: - NSURLSessionDataDelegate
  func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) {
    if (error != nil){
      self.client?.URLProtocol(self, didFailWithError: error!)
    }else{
      self.client?.URLProtocolDidFinishLoading(self)
    }
  }
  
  func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveResponse response: NSURLResponse, completionHandler: (NSURLSessionResponseDisposition) -> Void) {
    self.client?.URLProtocol(self, didReceiveResponse: response, cacheStoragePolicy: NSURLCacheStoragePolicy.NotAllowed)
    completionHandler(NSURLSessionResponseDisposition.Allow)
    
  }
  
  func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData) {
    self.client?.URLProtocol(self, didLoadData: data)
  }
  
  func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, willCacheResponse proposedResponse: NSCachedURLResponse, completionHandler: (NSCachedURLResponse?) -> Void) {
    
    completionHandler(proposedResponse)
    
  }


}

在子類中需實現(xiàn)4各方法
1.func canInitWithRequest(request: NSURLRequest) -> Bool//在此方法決定是否攔截請求马绝,return yes為攔截
2.func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest//在此方法修改請求并返回
3.func startLoading()//執(zhí)行特定的request請求
4.func stopLoading()//中斷特定的request請求
之后就是實現(xiàn)NSURLSession的代理方法(這里我不太了解豆赏,都是照著上面文章的代碼去寫)。

接下來還有做一步富稻,因為我們只是要修改webView的請求掷邦,所以我們可以在webview的VC的viewDidLoad方法中向NSURLProtocol注冊我們寫的子類

//注冊URLProtocol
      NSURLProtocol.registerClass(MyURLProtocol)

當然記得在deinit移除子類(deinit方法在swift中相當于OC中的dealloc)

deinit{
    
    NSURLProtocol.unregisterClass(MyURLProtocol)
  }

當然,如果我們想整個app的網(wǎng)絡請求都要修改的話椭赋,那我們就可以在application didFinishLaunchingWithOptions的方法里注冊我們的子類對象耙饰,就可以愉快地在整個app的網(wǎng)絡請求中為所欲為了,哈哈哈纹份。哦苟跪,放上我的demo,就這樣吧蔓涧。

結(jié)束

最近一直在思考件已,iOS程序員未來應該如何發(fā)展,內(nèi)心一直十分困惑元暴,望與諸君交流中解惑篷扩。學習之路,與君共勉茉盏。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鉴未,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子鸠姨,更是在濱河造成了極大的恐慌铜秆,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件讶迁,死亡現(xiàn)場離奇詭異连茧,居然都是意外死亡,警方通過查閱死者的電腦和手機巍糯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門啸驯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人祟峦,你說我怎么就攤上這事罚斗。” “怎么了宅楞?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵针姿,是天一觀的道長袱吆。 經(jīng)常有香客問我,道長搓幌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任迅箩,我火速辦了婚禮溉愁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘饲趋。我一直安慰自己拐揭,他們只是感情好,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布奕塑。 她就那樣靜靜地躺著堂污,像睡著了一般。 火紅的嫁衣襯著肌膚如雪龄砰。 梳的紋絲不亂的頭發(fā)上盟猖,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音换棚,去河邊找鬼式镐。 笑死,一個胖子當著我的面吹牛固蚤,可吹牛的內(nèi)容都是我干的娘汞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼夕玩,長吁一口氣:“原來是場噩夢啊……” “哼你弦!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起燎孟,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤禽作,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后揩页,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體领迈,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年碍沐,在試婚紗的時候發(fā)現(xiàn)自己被綠了狸捅。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡累提,死狀恐怖尘喝,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情斋陪,我是刑警寧澤朽褪,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布置吓,位于F島的核電站,受9級特大地震影響缔赠,放射性物質(zhì)發(fā)生泄漏衍锚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一嗤堰、第九天 我趴在偏房一處隱蔽的房頂上張望戴质。 院中可真熱鬧,春花似錦踢匣、人聲如沸告匠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽后专。三九已至,卻和暖如春输莺,著一層夾襖步出監(jiān)牢的瞬間戚哎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工嫂用, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留建瘫,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓尸折,卻偏偏與公主長得像啰脚,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子实夹,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

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