iOS - NetRequest 網絡數據請求

一、網絡請求

1.1 網絡通信三要素

  • 一、IP 地址(主機名):php

    • 網絡中設備的惟一標示。不易記憶,能夠用主機名(域名)。html

    • 1) IP V4:前端

      • 0~255.0~255.0~255.0~255 ,共有 2^8^4 = 2^32 = 42 億。
    • 2) 本地迴環地址:ios

      • 每臺機器都有本身的本地迴環地址,ip 爲 127.0.0.1 ,主機名爲 localhost。若是 127.0.0.1 ping 不通,則網卡不正常。git

      • 本地 hosts 文件修改,終端:程序員

        • $ cd /etc
        • $ sudo vim hosts
        • $ 輸入密碼進入 hosts 文件編輯界面
        • $ 將光標移動到指定位置
          - 英文輸入模式下按 i 鍵進入編輯狀態,
          - 英文輸入模式下按 esc 鍵進入命令狀態,
          - 在命令狀態下輸入 :wq 回車,保存退出 hosts 文件。
  • 二、端口號:github

    • 用於標示進程的邏輯地址,不一樣進程的標示。
    • 有效端口爲 0 ~ 65535,其中 0 ~ 1024 由系統使用或者保留端口,開發中不要使用 1024 如下的端口。web

    • 1) Netcat 的使用:算法

      • Netcat 是 Mac 終端下用於調試和檢查網絡的工具包,可用於建立 TCP/IP 鏈接。
      • 終端:$ nc -lk 12345,開啓監聽,終端將始終監聽本地計算機 12345 端口的數據。
  • 三、傳輸協議(通信的規則):數據庫

    • 1) TCP:傳輸控制協議:

      • 創建鏈接,造成傳輸數據的通道(創建鏈接的三次握手,斷開鏈接的四次握手)。
      • 在鏈接中進行大數據傳輸,數據大小不收限制。
      • 經過三次握手完成鏈接,是可靠協議,數據安全送達。
      • 必須創建鏈接,效率會稍低。
    • 2) UDP:用戶數據報協議:

      • 只管發送,不確認對方是否接收到。
      • 不須要創建鏈接,將數據及源和目的封裝成數據包中,每一個數據報的大小限制在 64K 以內。
      • 由於無需鏈接,所以是不可靠協議。
      • 不須要創建鏈接,速度快。
      • 應用場景:多媒體教室/網絡流媒體。
    • 3) 常見網絡協議:

      應用層協議       |      端口       |              說明

      -----------------|----------------|---------------------------------
      HTTP | 80 | 超文本傳輸協議
      HTTPS | 443 | HTTP+SSL,HTTP 的安全版
      FTP | 20, 21, 990 | 文件傳輸
      POP3 | 110 | 郵局協議
      SMTP | 25 | 簡單郵件傳輸協議
      telnet | 23 | 遠程終端協議

1.2 網絡參考模型

ISO 參考模型 TCP/IP 參考 說明
應用層 應用層 FTP,HTTP,TELNET,SMTP,DNS 等協議
表示層
會話層
傳輸層 傳輸層 Socket 開發,TCP 協議,UDP 協議
網絡層 網絡互連層 路由器,IP 協議,ICMP 協議,ARP 協議,RARP 協議和 BOOTP 協議
數據鏈路層 網絡接口層 交換機
物理層 網線

1.3 HTTP 請求

  • HTTP(HyperText Transfer Protocol 超文本傳輸協議)是一套計算機經過網絡進行通訊的規則。計算機專家設計出 HTTP,使 HTTP 客戶(如 Web 瀏覽器)可以從 HTTP 服務器(Web 服務器)請求信息和服務。HTTP 是一種無狀態的協議,無狀態是指 Web 瀏覽器和 Web 服務器之間不須要創建持久的鏈接,這意味着當一個客戶端向服務器端發出請求,而後 Web 服務器返回響應(response),鏈接就被關閉了,在服務器端不保留鏈接的有關信息。HTTP 遵循請求(Request)/應答(Response)模型。Web 瀏覽器向 Web 服務器發送請求,Web 服務器處理請求並返回適當的應答。全部 HTTP 鏈接都被構形成一套請求和應答。

1.3.1 HTTP 通訊機制

  • HTTP 通訊機制是在一次完整的 HTTP 通訊過程當中,Web 瀏覽器與 Web 服務器之間將完成下列 7 個步驟:

  • 一、創建 TCP 鏈接

    • 在 HTTP 工做開始以前,Web 瀏覽器首先要經過網絡與 Web 服務器創建鏈接,該鏈接是經過 TCP 來完成的,該協議與 IP 協議共同構建 Internet,即著名的 TCP/IP 協議族,所以Internet 又被稱做是 TCP/IP 網絡。HTTP 是比 TCP 更高層次的應用層協議,根據規則,只有低層協議創建以後才能進行更層協議的鏈接,所以,首先要創建 TCP 鏈接,通常 TCP 鏈接的端口號是 80。
  • 二、Web 瀏覽器向 Web 服務器發送請求命令

    • 一旦創建了 TCP 鏈接,Web 瀏覽器就會向 Web 服務器發送請求命令。例如:GET /sample/hello.jsp HTTP/1.1
  • 三、Web 瀏覽器發送請求頭信息

    • 瀏覽器發送其請求命令以後,還要以頭信息的形式向 Web 服務器發送一些別的信息,以後瀏覽器發送了一空白行來通知服務器,它已經結束了該頭信息的發送。
  • 四、Web 服務器應答

    • 客戶機向服務器發出請求後,服務器會給客戶機回送應答,HTTP/1.1 200 OK,應答的第一部分是協議的版本號和應答狀態碼。
  • 五、Web 服務器發送應答頭信息

    • 正如客戶端會隨同請求發送關於自身的信息同樣,服務器也會隨同應答向用戶發送關於它本身的數據及被請求的文檔。
  • 六、Web 服務器向瀏覽器發送數據

    • Web 服務器向瀏覽器發送頭信息後,它會發送一個空白行來表示頭信息的發送到此爲結束,接着,它就以 Content-Type 應答頭信息所描述的格式發送用戶所請求的實際數據。
  • 七、Web 服務器關閉 TCP 鏈接

    • 通常狀況下,一旦 Web 服務器向瀏覽器發送了請求數據,它就要關閉 TCP 鏈接,而後若是瀏覽器或者服務器在其頭信息加入了這行代碼,Connection:keep-alive,TCP 鏈接在發送後將仍然保持打開狀態,因而,瀏覽器能夠繼續經過相同的鏈接發送請求。保持鏈接節省了爲每一個請求創建新鏈接所需的時間,還節約了網絡帶寬。

1.3.2 HTTP 請求格式

  • 當瀏覽器向 Web 服務器發出請求時,它向服務器傳遞了一個數據塊,也就是請求信息,HTTP 請求信息由 3 部分組成:

    • 請求行:請求方法 請求路徑 協議/版本
    • 請求頭
    • 請求體

    • 如:

      GET /videos.jsp HTTP/1.1                   // 請求行
          Host: localhost                            // 請求頭
          User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:36.0) Gecko/20100101 Firefox/36.0
          Accept: text/html,application/xhtml+xml,application/xml;q=0.9,* / *;q=0.8
          Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
          Accept-Encoding: gzip, deflate
          Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7
          Connection: keep-alive
      
          username=jinqiao&password=1234             // 請求體
  • 一、請求行:

    • 請求的第一行,其組成爲:請求方法 請求路徑 協議/版本

      • 請求行 :GET /videos.jsp HTTP/1.1

      • 請求方法 :GET
      • 請求路徑 :/videos.jsp
      • 協議/版本:HTTP/1.1

    • (1) 請求方法:

      • 根據 HTTP 標準,HTTP 請求可使用多種請求方法。例如:HTTP1.1 支持 7 種請求方法:GET、POST、HEAD、OPTIONS、PUT、DELETE 和 TARCE。在 Internet 應用中,最經常使用的方法是 GET 和 POST。

      • GET 方法:

        • GET 方法是默認的 HTTP 請求方法,經過請求 URL 獲得資源。咱們平常用 GET 方法來提交表單數據,然而用 GET 方法提交的表單數據只通過了簡單的編碼,同時它將做爲 URL 的一部分向 Web 服務器發送,所以,若是使用 GET 方法來提交表單數據就存在着安全隱患上。例如:

          Http://127.0.0.1/login.jsp?Name=zhangshi&Age=30&Submit=%cc%E+%BD%BB

        • 從上面的 URL 請求中,很容易就能夠辯認出表單提交的內容。(?以後的內容)另外因爲 GET 方法提交的數據是做爲 URL 請求的一部分因此提交的數據量不能太大。

      • POST 方法:

        • POST 方法是 GET 方法的一個替代方法,用於添加新的內容。它主要是向 Web 服務器提交表單數據,尤爲是大批量的數據。POST 方法克服了 GET 方法的一些缺點。經過 POST 方法提交表單數據時,數據不是做爲 URL 請求的一部分而是做爲標準數據傳送給 Web 服務器,這就克服了 GET 方法中的信息沒法保密和數據量過小的缺點。所以,出於安全的考慮以及對用戶隱私的尊重,一般表單提交時採用 POST 方法。

        • 從編程的角度來說,若是用戶經過 GET 方法提交數據,則數據存放在 QUERY_STRING 環境變量中,而 POST 方法提交的數據則能夠從標準輸入流中獲取。

      • DELETE:刪除某個內容
      • CONNECT:用於代理進行傳輸,如使用 SSL
      • OPTIONS:詢問能夠執行哪些方法
      • PATCH:部分文檔更改
      • PROPFIND, (wedav):查看屬性
      • PROPPATCH, (wedav):設置屬性
      • MKCOL, (wedav):建立集合(文件夾)
      • COPY, (wedav):拷貝
      • MOVE, (wedav):移動
      • LOCK, (wedav):加鎖
      • UNLOCK (wedav):解鎖
      • TRACE:用於遠程診斷服務器
      • PUT :改
      • HEAD:相似於 GET, 只返回響應,不返回實體數據,用於檢查對象是否存在,以及獲得對象的元數據,下載數據前使用

      • apache2 中,可以使用 Limit,LimitExcept 進行訪問控制的方法包括:GET, POST, PUT, DELETE, CONNECT,OPTIONS, PATCH, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE,LOCK, 和 UNLOCK。其中, HEAD GET POST OPTIONS PROPFIND 是和讀取相關的方法,MKCOL PUT DELETE LOCK UNLOCK COPY MOVE PROPPATCH 是和修改相關的方法。

    • (2) 請求路徑:

      • 請求路徑(URI) 完整地指定了要訪問的網絡資源,一般只要給出相對於服務器的根目錄的相對目錄便可,所以老是以 「/」 開頭,最後,協議版本聲明瞭通訊過程當中使用 HTTP 的版本。
    • (3) 協議/版本:

      • HTTP/1.1
  • 二、請求頭:

    • 請求頭包含許多有關客戶端環境和請求體的有用信息。例如,請求頭能夠聲明瀏覽器所用的語言,請求體的長度等。當咱們打開一個網頁時,瀏覽器要向網站服務器發送一個 HTTP 請求頭,而後網站服務器根據 HTTP 請求頭的內容生成當次請求的內容發送給瀏覽器。

      Host: localhost                                                              // 請求主機
          User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:36.0) Gecko/20100101 Firefox/36.0   // 告訴服務器客戶端的類型
          Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8      // 告訴服務器客戶端支持的格式
          Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3                         // 告訴服務器客戶端的語言
          Accept-Encoding: gzip, deflate                                               // 告訴服務器客戶端支持的壓縮格式
          Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7                                   // 告訴服務器客戶端字符編碼
          Connection: keep-alive                                                       // 告訴服務器鏈接類型
          Content-Length: 4817                                                         // 提交給服務器的內容長度
          Content-Type: text/html                                                      // 提交給服務器的內容類型
          Authorization: authorString                                                  // 訪問服務器的驗證信息
          Range: bytes=0-499                                                           // 指定要返回的數據範圍
    • (1) Host

      • 表示請求的服務器網址。請求報頭域主要用於指定被請求資源的 Internet 主機和端口號,它一般從 HTTP URL 中提取出來的。

      • 例如: 咱們在瀏覽器中輸入:http://www.guet.edu.cn/index.html,瀏覽器發送的請求消息中,就會包含 Host 請求報頭域,以下:Host:http://www.guet.edu.cn,此處使用缺省端口號 80,若指定了端口號,則變成:Host:指定端口號

    • (2) User-Agent

      • 告訴 HTTP 服務器,客戶端使用的操做系統和瀏覽器的名稱和版本。

      • User-Agent(用戶代理),簡稱 UA,它是一個特殊字符串頭,使得服務器可以識別客戶端使用的操做系統及版本、CPU 類型、瀏覽器及版本、瀏覽器渲染引擎、瀏覽器語言、瀏覽器插件等。

      • 例如:User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; CIBA; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; .NET4.0C; InfoPath.2; .NET4.0E)

    • (3) Accept

      • 告訴服務器瀏覽器端能夠接受的媒體類型。

      • 客戶端支持的 MIME 類型分別是 text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8,優先順序是它們從左到右的排列順序。

      • text/html,application/xhtml+xml,application/xml 都是 MIME 類型,也能夠稱爲媒體類型和內容類型,斜槓前面的是 type(類型),斜槓後面的是 subtype(子類型);type 指定大的範圍,subtype 是 type 中範圍更明確的類型,即大類中的小類。

        • text :用於標準化地表示的文本信息,文本消息能夠是多種字符集和或者多種格式的;
        • text/html :表示 html 文檔;

        • application :用於傳輸應用程序數據或者二進制數據;
        • application/xhtml+xml :表示 xhtml 文檔;
        • application/xml :表示 xml 文檔。

      • q 是權重係數,範圍 0 =< q <= 1,q 值越大,請求越傾向於得到其 「;」 以前的類型表示的內容。
        • 若沒有指定 q 值,則默認爲 1。
        • 若被賦值爲 0,則用於提醒服務器哪些是瀏覽器不接受的內容類型。
    • (4) Accept-Language

      • 告訴服務器瀏覽器申明本身接收的語言。

      • 語言跟字符集的區別:中文是語言,中文有多種字符集,好比 big5,gb2312,gbk 等等;

      • 例如:Accept-Language: en-us

      • zh-cn :表示簡體中文
      • zh :表示中文

    • (5) Accept-Encoding

      • 瀏覽器申明本身接收的編碼方法,一般指定壓縮方法,是否支持壓縮,支持什麼壓縮方法(gzip,deflate),(注意:這不是隻字符編碼);

      • 例如:Accept-Encoding: gzip, deflate

      • gzip :是 GNU zip 的縮寫,它是一個 GNU 自由軟件的文件壓縮程序,也常常用來表示 gzip 這種文件格式
      • deflate :是同時使用了 LZ77 算法與哈夫曼編碼(Huffman Coding)的一個無損數據壓縮算法

    • (6) Accept-Charset

      • 瀏覽器申明本身接收的字符集,這就是本文前面介紹的各類字符集和字符編碼,如 gb2312,utf-8(一般咱們說Charset包括了相應的字符編碼方案);

      • GB2312 :是中國國家標準簡體中文字符集,全稱《信息交換用漢字編碼字符集·基本集》,又稱 GB0,由中國國家標準總局發佈,1981年5月1日實施
      • utf-8 :是 Unicode 的一種變長字符編碼又稱萬國碼,由 Ken Thompson 於 1992 年建立,如今已經標準化爲 RFC 3629
      • * :表示任意字符編碼,雖然 q 都是等於 0.7,但明確指定的 GB2312,utf-8 比 * 具備更高的優先級

    • (7) Connection

      • 告訴服務器鏈接類型。

      • Connection:Keep-Alive :表示持久鏈接,長鏈接。當一個網頁打開完成後,客戶端和服務器之間用於傳輸 HTTP 數據的 TCP 鏈接不會關閉,若是客戶端再次訪問這個服務器上的網頁,會繼續使用這一條已經創建的鏈接。

      • Connection:close :表明一個 Request 完成後,客戶端和服務器之間用於傳輸 HTTP 數據的 TCP 鏈接會關閉,當客戶端再次發送 Request,須要從新創建 TCP 鏈接。

      • 長鏈接:連上服務器就不斷開。雙方傳遞數據,不須要再次創建鏈接。

        • 優勢:效率高,一般只有很是有錢的公司,纔會提供長鏈接的服務。好比:apple 的消息推送服務就是長鏈接。
        • 缺點:用戶體驗很差,並且服務器的負擔很重。
      • 短鏈接:連上服務器,獲取完數據,就當即斷開。HTTP 訪問,都是短鏈接,使用狀況很是多。

    • (8) Content-Length

      • 發送給HTTP服務器數據的長度。

      • 例如: Content-Length:38

    • (9) Content-Type

      • 提交給服務器的內容類型

      • 例如:Content-Type: application/x-www-form-urlencoded

    • (10) Authorization

      • 訪問服務器的驗證信息
    • (11) Range

      • 指定要返回的數據範圍

      • - :用於分隔,前面的數字表示起始字節數,後面的數組表示截止字節數,沒有表示到末尾。

        • 如:bytes=0-499 從 0 到 499 的頭 500 個字節,bytes=500- 從 500 字節之後的全部字節
      • , :用於分組,能夠一次指定多個 Range,不過不多用。

        • 如:bytes=500-599,800-899 同時指定幾個範圍
    • (12) Referer

      • 提供了 Request 的上下文信息的服務器,告訴服務器我是從哪一個連接過來的,好比從我主頁上連接到一個朋友那裏,他的服務器就可以從 HTTP Referer中統計出天天有多少用戶點擊我主頁上的連接訪問他的網站。

      • 例如: Referer:http://translate.google.cn/?hl=zh-cn&tab=wT

    • (13) Pragma

      • 防止頁面被緩存,在 HTTP/1.1 版本中,它和 Cache-Control:no-cache 做用如出一轍,Pargma 只有一個用法,

      • 例如:Pragma:no-cache

    • (14) Cookie

      • 最重要的 header, 將 cookie 的值發送給 HTTP 服務器。
  • 三、請求體:

    • 請求頭和請求體之間是一個空行,這個行很是重要,它表示請求頭已經結束,接下來的是請求體。請求體中能夠包含客戶提交的查詢字符串信息。如:

      username=jinqiao&password=1234

    • 在以上的例子的 HTTP 請求中,請求的正文只有一行內容。固然,在實際應用中,HTTP 請求體能夠包含更多的內容。

1.3.3 HTTP 響應格式

  • HTTP 應答與 HTTP 請求類似,HTTP 響應也由 3 個部分構成,分別是:

    • 狀態行:協議/版本 狀態碼 狀態碼描述
    • 響應頭
    • 響應正文

    • 如:

      HTTP/1.1 200 OK                         // 狀態行
          Date: Wed, 29 Jun 2016 10:31:34 GMT     // 響應頭
          Server: Apache/2.4.18 (Unix)
          Content-Location: index.html.en
          Content-Length: 4817
          Content-Type: text/html
          Keep-Alive: timeout=5, max=100
      
          <html>                                  // 響應正文
              <body>
                  <h1>It works!</h1>
              </body>
          </html>
  • 一、狀態行:

    • HTTP 響應的第一行相似於 HTTP 請求的第一行,其組成爲:協議/版本 狀態碼 狀態碼描述

      • 狀態行 :HTTP/1.1 200 OK

      • 協議/版本:HTTP/1.1
      • 狀態碼 :200 OK

    • (1) 協議/版本:

      • HTTP/1.1
    • (2) 狀態碼:

      • HTTP 應答碼也稱爲狀態碼,它反映了 Web 服務器處理 HTTP 請求狀態。HTTP 應答碼由 3 位數字構成,其中首位數字定義了應答碼的類型:

        • 1XX-信息類(Information) :表示收到 Web 瀏覽器請求,正在進一步的處理中。
        • 2XX-成功類(Successful) :表示用戶請求被正確接收,理解和處理例如:200 OK。
        • 3XX-重定向類(Redirection) :表示請求沒有成功,客戶必須採起進一步的動做。
        • 4XX-客戶端錯誤(Client Error):表示客戶端提交的請求有錯誤,例如:404 NOT Found,意味着請求中所引用的文檔不存在。
        • 5XX-服務器錯誤(Server Error):表示服務器不能完成對請求的處理:如 500。
    • (3) 狀態碼描述:

      • 用來解析狀態碼的狀態。

      • 如:
        • 200 OK :請求已成功,請求所但願的響應頭或數據體將隨此響應返回。
        • 404 Not Found :請求失敗,請求所但願獲得的資源未被在服務器上發現。
  • 二、響應頭:

    • 響應頭也和請求頭同樣包含許多有用的信息,例如服務器類型、日期時間、內容類型和長度等:

      Date: Wed, 29 Jun 2016 10:31:34 GMT       // 訪問日期
          Server: Apache/2.4.18 (Unix)              // 訪問服務器的類型
          Content-Location: index.html.en           // 訪問的文件名
          Content-Length: 4817                      // 訪問文件的大小
          Content-Type: text/html                   // 訪問文件的類型
          Keep-Alive: timeout=5, max=100            // 鏈接類型
    • (1) Cache-Control

      • 這個是很是重要的規則。這個用來指定 Response-Request 遵循的緩存機制。各個指令含義以下

        • Cache-Control:Public 能夠被任何緩存所緩存
        • Cache-Control:Private 內容只緩存到私有緩存中
        • Cache-Control:no-cache 全部內容都不會被緩存
    • (2) Content-Type

      • WEB 服務器告訴瀏覽器本身響應的對象的類型和字符集。

      • 例如:
        • Content-Type:text/html; charset=utf-8
        • Content-Type:text/html;charset=GB2312
        • Content-Type:image/jpeg
    • (3) Expires

      • 瀏覽器會在指定過時時間內使用本地緩存
      • 例如: Expires:Tue, 08 Feb 2022 11:35:14 GMT
    • (4) Last-Modified

      • 用於指示資源的最後修改日期和時間。
      • 例如:Last-Modified: Wed, 21 Dec 2011 09:09:10 GMT
    • (5) Server

      • 指明 HTTP 服務器的軟件信息。
      • 例如:Server:Microsoft-IIS/7.5
    • (6) X-AspNet-Version

      • 若是網站是用 ASP.NET 開發的,這個 header 用來表示 ASP.NET 的版本。
      • 例如:X-AspNet-Version: 4.0.30319
    • (7) X-Powered-By

      • 表示網站是用什麼技術開發的。
      • 例如:X-Powered-By: ASP.NET
    • (8) Connection

      • 例如:Connection:keep-alive 當一個網頁打開完成後,客戶端和服務器之間用於傳輸 HTTP 數據的 TCP 鏈接不會關閉,若是客戶端再次訪問這個服務器上的網頁,會繼續使用這一條已經創建的鏈接。
      • 例如:Connection:close 表明一個 Request 完成後,客戶端和服務器之間用於傳輸 HTTP 數據的 TCP 鏈接會關閉,當客戶端再次發送 Request,須要從新創建 TCP 鏈接。
    • (9) Content-Length

      • 指明實體正文的長度,以字節方式存儲的十進制數字來表示。在數據下行的過程當中,Content-Length 的方式要預先在服務器中緩存全部數據,而後全部數據再一古腦兒地發給客戶端。
      • 例如:Content-Length: 19847
    • (10) Date

      • 生成消息的具體時間和日期。
      • 例如:Date: Sat, 11 Feb 2012 11:35:14 GMT
  • 三、響應正文:

    • 響應正文就是服務器返回的 HTML 頁面,響應頭和正文之間也必須用空行分隔。

      <html>
              <body>
                  <h1>It works!</h1>
              </body>
          </html>

1.3.4 安全鏈接

  • Web 應用最多見的用途之一是電子商務,能夠利用 Web 服務器端程序令人們可以網絡購物,須要指出一點是,缺省狀況下,經過 Internet 發送信息是不安全的,若是某人碰巧截獲了你發給朋友的一則消息,他就能打開它,假想在裏面有你的信用卡號碼,這會有多麼糟糕,幸運的是,不少 Web 服務器以及 Web 瀏覽器都有創立安全鏈接的能力,這樣它們就能夠安全的通訊了。

  • 經過 Internet 提供安全鏈接最多見的標準是安全套接層(Secure Sockets layer,SSl)協議。SSL 協議是一個應用層協議(和 HTTP 同樣),用於安全方式在 Web 上交換數據,SSL 使用公開密鑰編碼系統。從本質講,這意味着業務中每一方都擁有一個公開的和一個私有的密鑰。當一方使用另外一方公開密鑰進行編碼時,只有擁有匹配密鑰的人才能對其解碼。簡單來說,公開密鑰編碼提供了一種用於在兩方之間交換數據的安全方法,SSL 鏈接創建以後,客戶和服務器都交換公開密鑰,並在進行業務聯繫以前進行驗證,一旦雙方的密鑰都經過驗證,就能夠安全地交換數據。

1.4 WebDav 文件服務器

  • 基於 http 協議的 "文件" 服務器,實現文件的上傳/下載/修改/刪除。

  • WebDav 權限,受權信息的格式 BASIC (用戶名:口令)base64

  • 安全性並不高,密碼很容易被攔截和破解。

  • 應用場景:開發企業級的管理系統,能夠用 WebDav 搭建一個內部的文件管理服務器,只是在公司內網使用。

  • PUT 增,若是文件不存在,就是新增
  • DELETE 刪
  • PUT 改
  • GET 查

  • GET 不須要設置權限驗證,只是從服務器獲取數據。
  • PUT/DELETE 都須要設置權限驗證,新增(修改)/刪除 服務器的內容,須要權限驗證。

  • 請求狀態碼:

    • GET:
      • status code: 200 請求成功
      • status code: 404 文件不存在
    • PUT:
      • status code: 201 新增
      • status code: 204 修改

      • status code: 401 身份驗證失敗

    • DELETE:
      • status code: 204 刪除成功
      • status code: 404 文件不存在

      • status code: 401 身份驗證失敗

1.5 移動客戶端網絡請求

  • 對於移動客戶端來講,網絡的重要性不言而喻。常見的網絡請求有同步 GET,同步 POST,異步 GET,異步 POST。

  • 同步和異步網絡請求的區別:

    • 一、同步網絡請求,主線程負責數據的、視圖的初始化和界面的展現等。同步網絡數據請求也在主線程中進行,若是耗時較長,在數據請求完畢以前,其餘線程一概不響應,會對主線程形成阻塞,形成程序假死現象,用 戶體驗極差。

    • 二、異步網絡請求,主線程負責數據的、視圖的初始化和界面的展現等。異步網絡數據請求的時候,會在主線程以外單獨開闢一個線程去處理網絡請求,主線程依然處於可交互狀態,程序運行流暢。

    • 許多開發者都會認爲同步的鏈接將會堵塞主線程,其實這種觀點是錯誤的。一個同步的鏈接是會阻塞調用它的線程。若是你在主線程中建立一個同步鏈接,沒錯,主線程會阻塞。可是若是你並非從主線程開啓的一個同步的鏈接,它將會相似異步的鏈接同樣。所以這種狀況並不會堵塞你的主線程。事實上,同步和異步的主要區別就是運行 runtime 爲會異步鏈接建立一個線程,而同步鏈接則不會。

    • 使用 iOS 的網絡接口(NSURLSession/NSURLConnection)開發時,上傳和下載操做通常都是一條線程異步執行的。可是代理回調有多是多個線程。

  • GET 請求和 POST 請求的區別:

    • GET 請求:

      • GET 的本質是 "得",從服務器拿數據,效率更高,從數學的角度來說,GET 的結果是 "冪等" 的。
      • GET 請求可以被緩存。
      • 在 HTTP 協議定義中,沒有對 GET 請求的數據大小限制,不過由於瀏覽器不一樣,通常限制在 2~8K 之間。
      • GET 請求的接口會包含參數部分,全部參數包裝在 URL 中做爲網址的一部分。而且服務器的訪問日誌會記錄,不能傳遞敏感信息。
      • 參數格式:
        • 服務器資源路徑與參數之間經過 ? 來間隔。
        • 每個變量及值按照 變量名=變量值 方式設定,不能包含空格或者中文。
        • 多個參數使用 & 鏈接。
        • URL 字符串中若是包含中文,須要添加百分號轉義。
    • POST 請求:

      • POST 的本質是 "給",向服務器發送數據,也能夠得到服務器處理以後的結果,效率不如 GET。
      • POST 請求不能被緩存。
      • POST 提交數據比較大,大小靠服務器的設定值限制,PHP 一般限定 2M。
      • POST 請求會將服務器地址與參數分開,請求接口中只有服務器地址,而參數會做爲請求的一部分,提交後臺服務器。服務器日誌不會記錄參數,相對更安全。
      • 參數被包裝成二進制的數據體,格式與 GET 基本一致,只是不包含 ?。全部涉及用戶隱私的數據(密碼,銀行卡號)必定記住使用 POST 方式傳遞。
      • 雖然 GET 請求和 POST 請求均可以用來請求和提交數據,可是通常的 GET 多用於從後臺請求數據,POST 多用於向後臺提交數據。

1.6 iOS 網絡請求基本設置

  • 一、url:NSURL

    • 要訪問的資源路徑。

      + (nullable instancetype)URLWithString:(NSString *)URLString;
          + (nullable instancetype)URLWithString:(NSString *)URLString relativeToURL:(nullable NSURL *)baseURL;
    • 1) URL 結構:

      // 帶方括號 [] 的爲可選項
          scheme://host[:port]/path/[;parameters][?query]#fragment
      property url description
      URL https://swiftinaction.com/example?section=5&ie=utf-8 URL 路徑
      scheme https 協議,http、https、ftp、file(本地文件)、data(數據)
      host swiftinaction.com 主機,能夠利用 Reachability 框架判斷可否鏈接到要訪問的主機
      port nil 端口,nil 使用默認端口 80
      path example 路徑,不包含協議頭/主機地址/端口/參數
      parameters nil 參數,變量名和變量值成對出現,使用 = 分隔,多個參數使用 & 鏈接
      query section=5&ie=utf-8 查詢參數
      fragment nil 信息片斷
      absoluteString https://swiftinaction.com/example?section=5&ie=utf-8 完整的字符串
      resourceSpecifier //swiftinaction.com/example?section=5&ie=utf-8 不包含協議頭的剩餘內容
      baseURL nil 參照路徑,默認爲 nil
    • 2) URL 特殊字符處理:

      • 在一個 URL 中,全部的字符都必須是 ASCII 碼,不能包含特殊符號,好比 空格、中文等,若是有特殊符號須要使用百分號轉義。

      • 1> 百分號轉義編碼規則:

        • URL 中一些字符的特殊含義,基本編碼規則以下。
        字符 做用 十六進制值
        / 分隔目錄和子目錄 %2F
        ? 分隔 URL 和查詢參數 %3F
        & 分隔參數 %26
        # 指定書籤 %23
        % 指定特殊字符 %25
        " %22
        \ %5C
        ` 轉義 ` %60
        | 轉義 | %7C
        { 轉義 { %7B
        } 轉義 } %7D
        [ 轉義 [ %5B
        ] 轉義 ] %5D
        < 轉義 < %3C
        > 轉義 > %3E
        ^ 轉義 中文字符
        _ 轉義 空格 %20
      • 2> 百分號轉義 編碼:

        • stringByAddingPercentEscapesUsingEncoding 只對 ` # % ^ { } [ ] |  " < > 加 空格 共 14 個字符編碼,不包括 & ? 等符號,iOS9 中此方法被淘汰,建議用 stringByAddingPercentEncodingWithAllowedCharacters 方法,此方法中 Characters 的建立方式以下:

        • 編碼方式:

          // 轉義的字符包含 」#%/<>?@\^`{|}
              NSCharacterSet *allowedCharacters = [NSCharacterSet URLHostAllowedCharacterSet];
          
              // 轉義的字符包含 "#%;<>?[\]^`{|}
              NSCharacterSet *allowedCharacters = [NSCharacterSet URLPathAllowedCharacterSet];
          
              // 轉義的字符包含 "#%<>[\]^`{|}
              NSCharacterSet *allowedCharacters = [NSCharacterSet URLQueryAllowedCharacterSet];
          
              // 轉義的字符包含 "#%<>[\]^`{|}
              NSCharacterSet *allowedCharacters = [NSCharacterSet URLFragmentAllowedCharacterSet];
          
              // 轉義的字符包含 "#%/:<>?@[\]^`{|}
              NSCharacterSet *allowedCharacters = [NSCharacterSet URLPasswordAllowedCharacterSet];
          
              // 轉義的字符包含 "#%/:<>?@[\]^`
              NSCharacterSet *allowedCharacters = [NSCharacterSet URLUserAllowedCharacterSet];
          
              // 自定義方式
              NSCharacterSet *customAllowedSet = [NSCharacterSet characterSetWithCharactersInString:@"`#%^{}\"[]|\\<> "].invertedSet;
        • 使用:

          • 對整個 URL 進行轉義:

            NSString *urlStr = @"http://192.168.88.200/測試/demo.json";
            
                NSString *newUrlStr = [urlStr stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"^"].invertedSet];
            
                NSURL *url = [NSURL URLWithString:newUrlStr];
          • 對部分 URL 進行轉義:

            NSString *urlStr = [@"測試/demo.json" stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"^"].invertedSet];
            
                NSString *newUrlStr = [@"http://192.168.88.200" stringByAppendingPathComponent:urlStr];
            
                NSURL *url = [NSURL URLWithString:newUrlStr];
      • 3> 百分號轉義 解碼:

        • stringByRemovingPercentEncoding 在 Xcode7 中可能會提示要將 stringByAddingPercentEscapesUsingEncoding 替換成此方法,要根據是不是解碼來區分。
  • 二、request:NSURLRequest

    • 要發送給服務器的請求。

      + (instancetype)requestWithURL:(NSURL *)URL;
      
          + (instancetype)requestWithURL:(NSURL *)URL 
                             cachePolicy:(NSURLRequestCachePolicy)cachePolicy 
                         timeoutInterval:(NSTimeInterval)timeoutInterval;
    • 1) 參數:

      • 1> URL:要訪問的資源路徑

      • 2> cachePolicy:緩存策略

        // 默認的緩存策略,會在本地緩存
            NSURLRequestUseProtocolCachePolicy = 0,
        
            // 忽略本地緩存數據,永遠都是從服務器獲取數據,不使用緩存
            NSURLRequestReloadIgnoringLocalCacheData = 1,
        
            // 應用場景:股票,彩票
            NSURLRequestReloadIgnoringCacheData = NSURLRequestReloadIgnoringLocalCacheData
        
            // 首先使用緩存,若是沒有本地緩存,才從原地址下載
            NSURLRequestReturnCacheDataElseLoad = 2,
        
            // 使用本地緩存,從不下載,若是本地沒有緩存,則請求失敗和 "離線" 數據訪問有關,能夠和 Reachability 框架結合使用,
            // 若是用戶聯網,直接使用默認策略。若是沒有聯網,可使用返回緩存策略鄭重提示:要把用戶拉到網絡上來。
            NSURLRequestReturnCacheDataDontLoad = 3,
        
            // 無視任何緩存策略,不管是本地的仍是遠程的,老是從原地址從新下載
            NSURLRequestReloadIgnoringLocalAndRemoteCacheData = 4,      // Unimplemented
        
            // 若是本地緩存是有效的則不下載,其餘任何狀況都從原地址從新下載
            NSURLRequestReloadRevalidatingCacheData = 5,                // Unimplemented
        
            緩存的數據保存在沙盒路徑下 Caches 文件夾中的 SQLite 數據庫中。
      • 3> timeoutInterval:訪問超時時長

        • 默認的超時時長是 60s
        • 建議時長:15~30s,不要設置的過短.

        • SDWebImage : 15s
        • AFNetWorking: 60s

    • 2) NSURLRequest (NSHTTPURLRequest):

      • 1> HTTPMethod:請求方法

        • HTTP 訪問方法,如 GET(默認)、POST ...
      • 2> HTTPBody:請求體

        • 提交給服務器的二進制數據。
      • 3> HTTPShouldHandleCookies:是否須要處理 Cookies

        • 默認爲 YES,須要處理 Cookie。
      • 4> allHTTPHeaderFields:全部 HTTP 請求頭字典

    • 3) 請求行:

      • 包含了請求方法、請求資源路徑、HTTP協議版本。
    • 4) 請求頭:

      • 對客戶端的環境描述、客戶端請求的主機地址等信息。
    • 5) 請求體:

      • 客戶端發給服務器的具體數據。
  • 三、response:NSURLResponse

    • 從服務器返回的響應。

      void (^)(NSURLResponse* __nullable response, NSData* __nullable data, NSError* __nullable connectionError)
    • 1) 參數:

      • 1> response:服務器返回的響應

        • 包含狀態行和響應頭。
        • 通常只有在開發下載的時候,纔會使用 response。
      • 2> data

        • 服務器返回的數據實體,須要處理的二進制數據,最重要的。
      • 3> onnectionError

        • 訪問服務器過程當中,出現的鏈接錯誤。
        • 全部網絡訪問都有可能出現錯誤,在商業開發中,必定要作錯誤處理。
    • 2) NSURLResponse/NSHTTPURLResponse:

      • 1> statusCode:服務器返回的狀態碼

        • 1XX 消息,2XX 成功,3XX 擴展屬性,4XX 客戶端錯誤,5XX 服務器錯誤

        • 404 頁面沒找到
        • 301 沒有變化,可使用緩存
        • 200 成功

      • 2> URL:服務器返回的 URL

        • 有的時候,訪問服務器的時候,服務器會根據客戶端的環境作 「重定向」 鏈接,形成服務器返回的 URL 和本身添加的 URL 不相同。
        • 重定向是服務器來作的。
      • 3> MIMEType:數據類型

        • 返回二進制數據的類型。經過 MIMEType 能夠知道如何處理服務器返回的二進制數據。
        • 等價於 Content-Type。
      • 4> expectedContentLength:預期的數據長度

        • 主要用在下載,能夠用來提示用戶文件大小以及進度。
      • 5> suggestedFilename:建議的文件名

        • 跟下載有關,能夠默認將文件保存成建議的文件名,即便用文件在服務器端的名稱。
      • 6> textEncodingName:文本的編碼名稱

        • 若是沒有特殊指定,統一使用 UTF8。

        • 字符編碼:

          • UTF8: UNICODE 是一個字符編碼標準,UTF8 是 UNICODE 的一個子集。
            • 特色:使用 1~4 個字節描述一個字符。一個漢字是 3 個字節
            • 4G 個字符,可以涵蓋全世界全部的字符!
          • GB2312: 只是在一些比較老的網站還在使用,國標,1980 頒佈的標準,涵蓋了 6700+ 漢字
            • 漢字:最全的字典收錄了 85000+ 漢字,康熙字典 47000+
    • 3) 狀態行:

      • 包含了 HTTP 協議版本、狀態碼、狀態英文描述。
    • 4) 響應頭:

      • 包含了對服務器的描述、對返回數據的描述。
    • 5) 響應體:

      • 服務器返回給客戶端的具體二進制數據。
  • 四、請求結果處理:

    • 1) 服務器返回給客戶端的數據樣式:

      • 主要格式:字符串、JSON、XML、PList
      • 其餘格式:文件下載能夠返回任意格式、圖像、zip
    • 2) 序列化/反序列化:

      • 序列化:向服務器發送請求前,須要把提交給服務器的 OC 對象(NSArray / NSDictionary)轉換成二進制數據。
      • 反序列化:從服務器接收到數據後,須要將服務器返回的二進制數據轉換成 OC 對象(NSArray / NSDictionary)。
    • 3) 錯誤處理標準代碼:

      // 有的時候,沒有錯誤,可是也獲取不到數據
          if (error != nil || data == nil) {
      
          // 不要告訴用戶太準確的錯誤信息
          NSLog(@"您的網絡不給力,請稍候再試 !");
              return;
          }
      
          NSLog(@"網絡請求成功 %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);

1.7 iOS App Transport Security

  • iOS9 引入了新特性 App Transport Security (ATS),新特性要求 App 內訪問的網絡必須使用 HTTPS 協議。iOS9 把全部的 http 請求都改成 https,系統發送的網絡請求將統一使用 TLS 1.2 SSL。採用 TLS 1.2 協議,目的是強制加強數據訪問安全,並且系統 Foundation 框架下的相關網絡請求,將再也不默認使用 Http 等不安全的網絡協議,而默認採用 TLS 1.2。服務器所以須要更新,以解析相關數據。如不更新,可經過在 Info.plist 中聲明,倒退回不安全的網絡請求。

  • 一、關閉強制 https 請求:

    • 設置以下,添加 App Transport Security Settings 項,在其下添加 Allows Arbitrary Loads 並設置值爲 YES。

      NetRequest1

    • 設置代碼以下:

      <key>NSAppTransportSecurity</key>
          <dict>
              <key>NSAllowsArbitraryLoads</key>
              <true/>
          </dict>
  • 二、設置 http 請求例外:

    • 設置以下,NSIncludeSubdomains 顧名思義是包括子域的意思。

      NetRequest2

    • 設置代碼以下:

      <key>NSAppTransportSecurity</key>
          <dict>
              <key>NSExceptionDomains</key>
              <dict>
                  <key>qq.com</key>
                  <dict>
                      <key>NSIncludesSubdomains</key>
                      <true/>
                  </dict>
                  <key>sina.com.cn</key>
                  <dict>
                      <key>NSIncludesSubdomains</key>
                      <true/>
                  </dict>
              </dict>
          </dict>

1.8 iOS POST 經常使用方法

  • 一、URL 編碼表單數據

    • Content-Type: application/x-www-form-urlencoded

    • 主要向服務器提交與用戶隱私相關的信息。好比用戶登陸。

    • 1) 特色:

      這種方式訪問服務器,只須要指定訪問方法和數據體便可。
            Content-Type 和 Content-Length 會自動完成。Content-Type 是客戶端告訴服務器發送數據的類型。Content-Length 發送的數據長度。
    • 2) 實現代碼:

      request.HTTPMethod = @"POST";
            request.HTTPBody = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
      
            在 firebug 中,能夠經過 POST -> 源代碼,將發送的 httpbody 的內容粘貼出來。
  • 二、二進制數據 編碼表單數據

    • Content-Type: multipart/form-data

    • 向服務器上傳文件,可以上傳文件的大小受服務器限制,PHP 限制是 2M。

    • 1) 實現代碼:

      request.HTTPMethod = @"POST";
          request.HTTPBody = 使用規定的格式拼接
      
          // 設置請求頭格式,如:Content-Type: multipart/form-data; boundary=%@
          Content-Type: multipart/form-data; boundary(分隔線)=(能夠隨便寫,ASCII,字母和數字)
      
          // 設置文件類型格式,8 進制流,若是不想告訴服務器具體的文件類型,可使用這個
          Content-Type: application/octet-stream
    • 2) 文件上傳參數設置:

      • name (file) :後臺規定的文件字段名,是負責上傳文件的腳本中的字段名,開發的時候,能夠諮詢後端程序員。對文件上傳時是數組的形式,如:userfile[]
      • filename :將文件保存在服務器上的文件名稱。
      • Content-Type:客戶端告訴服務器上傳文件的文件類型。

        • 文件類型:

          image/jpeg 圖片文件
          image/png 圖片文件
          image/gif 圖片文件
          audio/mpeg mp3 文件
          video/mp4 mp4 文件
          text/html html 文本文件
          text/plain txt 文本文件
          text/rtf rtf 文本文件
          application/pdf pdf 文件
          application/json json 文件
          application/octet-stream 8 進制流,若是不想告訴服務器具體的文件類型,可使用這個
      • name (text) :後臺規定的文本內容字段名,是負責上傳文件的腳本中的字段名

    • 3) 文件上傳數據封裝:

      • 每一行末尾須要有必定的 \r\n
      • 有些服務器能夠直接使用 \n,可是新浪微博若是使用 \n 上傳文件,服務器會返回 「沒有權限」 的錯誤。
      • 有些服務器能夠在上傳文件的同時,提交一些文本內容給服務器。典型應用:新浪微博,上傳圖片的同時,發送一個微博。

      • 如下部分,是發送給服務器的二進制數據的組成格式,若是在 iOS 中,要實現 POST 上傳文件,須要按照如下格式拼接數據。格式是 W3C 指定的標準格式,蘋果沒有作任何封裝。

      • 1> 上傳單個文件

        #define boundary @"uploadBoundary"
        
            // 設置請求頭
        
            Content-Type: multipart/form-data; boundary=boundary
        
            // 上傳的文件數據封裝 --- 二進制數據格式
        
            --boundary\r\n
            Content-Disposition: form-data; name="userfile"; filename="文件1.txt"\r\n      // 設置文件名
            Content-Type: application/octet-stream\r\n                                    // 設置文件類型
            \r\n
            待上傳文件的二進制數據
            \r\n
        
            --boundary\r\n
            Content-Disposition: form-data; name="usertext"\r\n                           // 設置文本字段名
            \r\n
            待上傳文本內容二進制數據
            \r\n
        
            --boundary--
            \r\n
      • 2> 上傳多個文件

        #define boundary @"uploadBoundary"
        
            // 設置請求頭
        
            Content-Type: multipart/form-data; boundary=boundary
        
            // 上傳的文件數據封裝 --- 二進制數據格式
        
            --boundary\r\n
            Content-Disposition: form-data; name="userfile[]"; filename="文件1.txt"\r\n     // 設置文件名,第一個上傳的文件
            Content-Type: application/octet-stream\r\n                                     // 設置文件類型
            \r\n
            待上傳文件的二進制數據
            \r\n
        
            --boundary\r\n
            Content-Disposition: form-data; name="userfile[]"; filename="文件2.txt"\r\n     // 設置文件名,第二個上傳的文件
            Content-Type: application/octet-stream\r\n                                     // 設置文件類型
            \r\n
            待上傳文件的二進制數據
            \r\n
        
            --boundary\r\n
            Content-Disposition: form-data; name="usertext"\r\n                            // 設置文本字段名
            \r\n
            待上傳文本內容二進制數據
            \r\n
        
            --boundary--                                                                   // 結束分割線標記
            \r\n
    • 4) 關於第三方框架:

      • AFN 可以同時實現上傳 "一個文件",有些格式的文件,用 AFN 沒法上傳。
      • ASI 可以同時實現上傳多個文件,是 MRC 的,2012 年就中止更新了,設計的目標平臺,iOS 2.0/iOS 3.0 用的。
    • 5) 爲何要同時上傳多個文件:

      • 之前不少服務器對上傳文件的大小有限制,PHP 限制是 2M。
      • 目前不少服務器不只不限制大小,並且鼓勵上傳多個文件。
      • 雲服務器的普及。
      • 軟件商但願得到更多的用戶數據。
  • 三、RESTful 設計風格

    • RESTful 的設計風格,讓後端的設計更加直觀,解讀起來很是容易。目前在國際上很是流行,國內也開始逐漸普及。
    • 主要用在後端開發的,前端程序員只要知道便可。

    • 1) 最直觀的特色:

      • 沒有腳本文件的擴展名,直接就是語義的表達。
    • 2) 主要的表現形式:

      • 使用一個 URL,使用不一樣的 HTTP 訪問方法,表達不一樣的語義。

      • 示例:http://www.xxx.com/product/123

        • GET http://www.xxx.com/product/123 語義:從服務器 "獲取" 產品代號是123 的產品信息
        • POST http://www.xxx.com/product/123 語義:在服務器 "新增" 產品代號是123 的產品記錄
        • PUT http://www.xxx.com/product/123 語義:在服務器 "修改" 產品代號是123 的產品記錄
        • DELETE http://www.xxx.com/product/123 語義:在服務器 "刪除" 產品代號是123 的產品記錄

        • POST 提交二進制數據,須要提交一個 JSON 格式的二進制數據,後端程序員,能夠直接反序列化,獲得 JSON 中的字典信息。

        • 分別對應:增,刪,改,查

    • 3) POST 數據編碼類型:

      • 1> Content-Type: application/json

        • 向服務器發送 JSON 數據。

          [p dictionaryWithValuesForKeys:@[@"username", @"age", @"title", @"height"]];        模型轉字典,傳入的數組是須要序列化的屬性
              [NSJSONSerialization isValidJSONObject:obj];                                        判斷給定的對象可以被序列化
              [NSJSONSerialization dataWithJSONObject:obj options:0 error:NULL];                  序列化
      • 2> Content-Type: text/xml

        • 向服務器發送 XML 數據。

        • iOS 開發極少用,若是開發中碰到可使用 GData 框架。

1.9 iOS 文件下載設置

  • 一、HEAD 方法:

    • HEAD 方法一般是用來在下載文件以前,獲取遠程服務器上的文件信息。與 GET 方法相比,一樣可以拿到響應頭,可是不返回數據實體,用戶能夠根據響應頭信息,肯定下一步操做。

    • 用響應頭的 response.expectedContentLength 能夠獲取文件數據的大小。

    • 同步方法是阻塞式的,一般只有 HEAD 方法(得到的數據不多,並且後續的下載會依賴)纔會使用同步方法。在截取網絡數據的時候,最好使用同步方法,並且若是頻率過高,須要增長延時,不然會被服務器給加入黑名單。

  • 二、文件下載方法:

    • 1) 使用 GET 數據請求方法,數據請求完成後,將數據手動寫入文件中。

    • 2) 使用專門用於下載的 GET 方法,數據請求完成後,將會自動寫入指定文件中。

  • 三、文件本地保存方法:

    • 1) 拼接數據,統一寫入磁盤
      • 問題:內存峯值可能會很高。
    • 2) 每次接收到二進制數據,都直接寫入磁盤
      • NSFileHandle 文件句柄寫入
      • NSOutputStream 文件流寫入
  • 四、文件斷點下載步驟:

    • 1) 檢查服務器上的文件信息:
      • 文件大小
      • 文件名
    • 2) 檢查本地文件信息:
      • 1> 本地沒有文件,從頭開始下載
      • 2> 本地有文件,比服務器小,從本地文件大小開始下載
      • 3> 本地有文件,和服務器同樣大,表示下載完成
      • 4> 本地有文件,比服務器大,刪除本地文件,從新下載
    • 3) 根據本地文件的長度,從對應 "偏移" 位置開始下載:

      • 請求頭設置 Range:
        • bytes=x-y 從 x 字節開始下載,下載 x-y 個字節
        • bytes=x- 從 x 字節開始下載,下載到文件末尾
        • bytes=-x 從 文件開始下載,下載 x 字節

        • 如:[urlRequest setValue:[NSString stringWithFormat:@"bytes=%lld-", offset] forHTTPHeaderField:@"Range"];

  • 五、文件下載設置:

    • 1) NSURLConnection:

      • 代理方法默認都是在主線程上執行的,會對界面產生卡頓。

      • For the connection to work correctly, the calling thread’s run loop must be operating in the default run loop mode.
      • 爲了讓鏈接工做正常,調用線程的運行循環必須在默認的運行循環模式下。

      • 若是要讓 NSURLConnection 實如今後臺線程回調代理方法,須要在後臺線程啓動 NSURLConnection,並啓動後臺線程的運行循環,NSURLConnection 執行完畢後,會自動中止後臺線程的運行循環。

    • 2) NSURLSession:

      • 文件下載成功後,若是不作任何處理,下載的文件會被自動刪除。
      • 若是顯示比較大的圖片,NSURLSession 能夠利用磁盤緩存直接下載到本地,不會形成內存佔用太大。

      • 通常從網絡上下載文件,zip 壓縮包會比較多。若是是 zip 文件,下載完成後須要:
        • 下載壓縮包
        • 解壓縮(異步執行)到目標文件夾
        • 刪除壓縮包
      • 下載任務的特色可讓程序員只關心解壓縮的工做。

    • 3) 啓動子線程的運行循環方法:

      CFRunLoopRun();
      
          // NSRunLoop 只能啓動,沒有提供中止的接口
          [[NSRunLoop currentRunLoop] run];
  • 六、塊代碼回調:

    • 1) Block 的屬性定義:

      • 若是本方法可以直接執行到 block,就不須要定義 block 屬性。
      • 若是本方法不能直接執行 block,就須要定義 block 屬性。
    • 2) 網絡 block 回調的幾個 "約定":

      • AFN/SDWebImage 等第三方框架,都是這麼作的。

      • 1> 進度的回調,在異步回調
        • 進度的頻率很是高,若是在某些 UI 上高頻率回調進度,會形成界面卡頓。
        • 若是須要,就在主線程更新 UI,若是卡的太厲害,就想別的解決方法,如使用旋轉的小菊花等。
      • 2> 成功的回調,在主線程回調
        • 成功只有一個,在主線程回調,調用方不須要考慮線程間通信。
      • 3> 失敗的回調,能夠在主線程,也能夠在後臺線程

二、同步 GET 網絡請求

  • Objective-C

    • NSURLConnection 同步請求

      // 設置網絡接口
          NSURL *url1 = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video?type=JSON"];
      
          // 建立同步網絡請求
          NSData *syncNetData1 = [NSURLConnection sendSynchronousRequest:[NSURLRequest requestWithURL:url1] 
                                                       returningResponse:nil 
                                                                   error:NULL];
    • NSData 同步請求

      // 設置網絡接口
          NSURL *url2 = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video?type=JSON"];
      
          // 建立同步網絡請求
          NSData *syncNetData2 = [NSData dataWithContentsOfURL:url2];
    • NSString 同步請求

      // 設置網絡接口
          NSURL *url3 = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video?type=JSON"];
      
          // 建立同步網絡請求
          NSString *syncNetString = [NSString stringWithContentsOfURL:url3 encoding:NSUTF8StringEncoding error:nil];
    • WebView 同步請求

      // 設置網絡接口
          NSURL *url4 = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer"];
      
          // 建立同步網絡請求
          [self.webView loadRequest:[NSURLRequest requestWithURL:url4]];
  • Swift

    • NSURLConnection 同步請求

      // 設置網絡接口
          let url1 = NSURL(string: "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
          // 建立同步網絡請求
          let syncNetData1 = try! NSURLConnection.sendSynchronousRequest(NSURLRequest(URL: url1!), returningResponse: nil)
    • NSData 同步請求

      // 設置網絡接口
          let url2 = NSURL(string: "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
          // 建立同步網絡請求
          let syncNetData2 = NSData(contentsOfURL: url2!)
    • NSString 同步請求

      // 設置網絡接口
          let url3 = NSURL(string: "http://192.168.88.200:8080/MJServer/video?type=JSON")
      
          // 建立同步網絡請求
          let syncNetString = try! NSString(contentsOfURL: url3!, encoding: NSUTF8StringEncoding)
    • WebView 同步請求

      // 設置網絡接口
          let url4 = NSURL(string: "http://192.168.88.200:8080/MJServer")
      
          // 建立同步網絡請求
          self.webView.loadRequest(NSURLRequest(URL: url4!))

三、同步 POST 網絡請求

  • Objective-C

    // 設置網絡接口
        NSURL *url = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video"];
    
        // 建立請求
        NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
    
        // 設置請求體(請求參數)
        urlRequest.HTTPBody = [@"type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
    
        // 設置請求方式
        urlRequest.HTTPMethod = @"POST";
    
        // 建立同步連接
        NSData *syncNetData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:nil error:nil];
  • Swift

    // 設置網絡接口
        let url = NSURL(string: "http://192.168.88.200:8080/MJServer/video")
    
        // 建立請求
        let urlRequest = NSMutableURLRequest(URL: url!)
    
        // 設置請求體(請求參數)
        urlRequest.HTTPBody = "type=JSON".dataUsingEncoding(NSUTF8StringEncoding)
    
        // 設置請求方式
        urlRequest.HTTPMethod = "POST"
    
        // 建立同步連接
        let syncNetData = try? NSURLConnection.sendSynchronousRequest(urlRequest, returningResponse: nil)

四、異步 GET 網絡請求

  • Objective-C

    // 設置網絡接口
        NSURL *url = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video?type=XML"];
    
        // 建立異步網絡請求
        [NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:url] 
                                           queue:[NSOperationQueue mainQueue] 
                               completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    
        }];
  • Swift

    // 設置網絡接口
        let url = NSURL(string: "http://192.168.88.200:8080/MJServer/video?type=XML")
    
        // 建立異步網絡請求
        NSURLConnection.sendAsynchronousRequest(NSURLRequest(URL: url!), 
                                          queue: NSOperationQueue.mainQueue()) 
                                               { (response:NSURLResponse?, data:NSData?, connectionError:NSError?) in
    
        }

五、異步 POST 網絡請求

  • Objective-C

    // 設置網絡接口
        NSURL *url = [NSURL URLWithString:@"http://192.168.88.200:8080/MJServer/video"];
    
        // 建立請求
        NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
    
        // 設置請求體(請求參數)
        urlRequest.HTTPBody = [@"type=XML" dataUsingEncoding:NSUTF8StringEncoding];
    
        // 設置請求方式
        urlRequest.HTTPMethod = @"POST";
    
        // 建立異步鏈接
        [NSURLConnection sendAsynchronousRequest:urlRequest 
                                           queue:[NSOperationQueue mainQueue] 
                               completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    
        }];
  • Swift

    // 設置網絡接口
        let url = NSURL(string: "http://192.168.88.200:8080/MJServer/video")
    
        // 建立請求
        let urlRequest = NSMutableURLRequest(URL: url!)
    
        // 設置請求體(請求參數)
        urlRequest.HTTPBody = "type=XML".dataUsingEncoding(NSUTF8StringEncoding)
    
        // 設置請求方式
        urlRequest.HTTPMethod = "POST"
    
        // 建立異步網絡請求
        NSURLConnection.sendAsynchronousRequest(urlRequest, 
                                          queue: NSOperationQueue.mainQueue()) 
                                               { (response:NSURLResponse?, data:NSData?, connectionError:NSError?) in
    
        }

六、網絡請求基本設置

  • Objective-C

    // 設置網絡接口
        NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/demo.json"];
    
        // 建立網絡請求
        NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:15.0];
    
        // 發送網絡鏈接
        [[[NSURLSession sharedSession] dataTaskWithRequest:request 
                                         completionHandler:^(NSData * _Nullable data, 
                                                      NSURLResponse * _Nullable response, 
                                                            NSError * _Nullable error) {
    
            /*
                網絡請求完成,處理請求結果,error != nil || data == nil 請求失敗。
            */
    
            // 錯誤處理的標準代碼 - 有的時候,沒有錯誤,可是也獲取不到數據
            if (error != nil || data == nil) {
    
                // 不要告訴用戶太準確的錯誤信息
                NSLog(@"您的網絡不給力,請稍候再試 !");
    
                return;
            }
    
            // 請求數據解析
            id result = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
    
            NSLog(@"網絡請求成功 %@", result);
    
        }] resume];

七、文件上傳設置

  • Objective-C

    • 單文件上傳

      // 設置網絡接口
          NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/upload/upload.php"];
      
          // 建立網絡請求                                              
          NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
          request.HTTPMethod = @"POST";
      
          // 設置請求頭
      
              #define boundary @"uploadBoundary"
      
              [request setValue:[NSString stringWithFormat:@"multipart/form-data; charset=utf-8; boundary=%@", boundary] 
                       forHTTPHeaderField:@"Content-Type"];
      
          // 設置上傳的文件數據
      
              NSMutableData *formDataM = [NSMutableData data];
      
              // 添加文件
      
              [formDataM appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
              [formDataM appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; 
                                                                                  name=\"%@\"; 
                                                                              filename=\"%@\"\r\n", @"userfile", @"test.jpg"] 
                                                                              dataUsingEncoding:NSUTF8StringEncoding]];
              [formDataM appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n", @"image/jpeg"] 
                                                                              dataUsingEncoding:NSUTF8StringEncoding]];
      
              [formDataM appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
      
              // 本地待上傳的文件
              [formDataM appendData:[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"HQ_0005" ofType:@"jpg"]]];
              [formDataM appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
      
              // 添加文本
      
              [formDataM appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
              [formDataM appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; 
                                                                                  name=\"%@\"\r\n\r\n%@\r\n", @"username", @"qian"]
                                                                              dataUsingEncoding:NSUTF8StringEncoding]];
      
              // 添加結束分隔符
      
              [formDataM appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
      
          [[[NSURLSession sharedSession] uploadTaskWithRequest:request 
                                                      fromData:formDataM 
                                             completionHandler:^(NSData * _Nullable data, 
                                                          NSURLResponse * _Nullable response, 
                                                                NSError * _Nullable error) {
      
              if (error != nil || data == nil) return;
      
              id result = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
              [self refreshUI:result];
          }] resume];
    • 單文件上傳簡單封裝

      • 文件數據封裝使用到第三方框架 QExtension,具體實現代碼見 GitHub 源碼 QExtension
      // NSData+FormData.m
              。。。。。
      
          // 設置上傳的文件數據
      
              #define boundary @"uploadBoundary"
      
              NSMutableData *formDataM = [NSMutableData data];
      
              [formDataM q_setHttpHeaderFieldWithRequest:request fileBoundary:boundary];               // 設置請求頭
      
              [formDataM q_appendPartWithFileURL:[NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"HQ_0005" ofType:@"jpg"]] 
                                    fileBoundary:boundary name:@"userfile" 
                                        fileName:nil 
                                        mimeType:nil];                                                 // 添加文件
      
              [formDataM q_appendPartWithText:@"qian" textName:@"username" fileBoundary:boundary];     // 添加文本
      
              [formDataM q_appendPartEndingWithFileBoundary:boundary];                                 // 添加結束分隔符
    • 單文件上傳封裝

      • 文件數據封裝使用到第三方框架 QExtension,具體實現代碼見 GitHub 源碼 QExtension
      // NSData+FormData.m
              。。。。。
      
          // 設置上傳的文件數據
      
              // 指定文件數據方式
      
              NSData *filedata = [[NSData alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"HQ_0003" ofType:@"jpg"]];
      
              NSData *formData = [NSData q_formDataWithRequest:request 
                                                      fileData:filedata 
                                                          name:@"userfile" 
                                                      fileName:@"HQ_0003.jpg" 
                                                      mimeType:@"image/jpeg"];
      
              NSData *formData = [NSData q_formDataWithRequest:request 
                                                          text:@"qian" 
                                                      textName:@"username" 
                                                      fileData:filedata 
                                                          name:@"userfile" 
                                                      fileName:@"HQ_0003.jpg" 
                                                      mimeType:@"image/jpeg"];
      
              // 指定文件路徑方式
      
              NSURL *fileURL = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"HQ_0005" ofType:@"jpg"]];
      
              NSData *formData = [NSData q_formDataWithRequest:request 
                                                       fileURL:fileURL 
                                                          name:@"userfile" 
                                                      fileName:@"test.jpg" 
                                                      mimeType:@"image/jpeg"];
      
              NSData *formData = [NSData q_formDataWithRequest:request 
                                                          text:@"qian" 
                                                      textName:@"username" 
                                                       fileURL:fileURL 
                                                          name:@"userfile" 
                                                      fileName:@"test.jpg" 
                                                      mimeType:@"image/jpeg"];
    • 多文件上傳

      // 設置網絡接口
          NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/upload/upload-m.php"];
      
          // 建立網絡請求
          NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
          request.HTTPMethod = @"POST";
      
          // 設置請求頭
      
              #define boundary @"uploadBoundary"
      
              [request setValue:[NSString stringWithFormat:@"multipart/form-data; charset=utf-8; boundary=%@", boundary] 
                       forHTTPHeaderField:@"Content-Type"];
      
          // 設置上傳的文件數據
      
              NSMutableData *formDataM = [NSMutableData data];
      
              // 添加第一個文件
      
              [formDataM appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
              [formDataM appendData:[[NSString stringWithFormat:@"Content-Disposition:form-data;
                                                                                 name=\"%@\";
                                                                             filename=\"%@\"\r\n", @"userfile[]", @"test1.jpg"]
                                                                             dataUsingEncoding:NSUTF8StringEncoding]];
              [formDataM appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n", @"image/jpeg"] 
                                                                             dataUsingEncoding:NSUTF8StringEncoding]];
              [formDataM appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
              [formDataM appendData:[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"HQ_0003" ofType:@"jpg"]]];
              [formDataM appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
      
              // 添加第二個文件
      
              [formDataM appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
              [formDataM appendData:[[NSString stringWithFormat:@"Content-Disposition:form-data;
                                                                                 name=\"%@\";
                                                                             filename=\"%@\"\r\n", @"userfile[]", @"test2.jpg"]
                                                                             dataUsingEncoding:NSUTF8StringEncoding]];
              [formDataM appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n", @"image/jpeg"] 
                                                                             dataUsingEncoding:NSUTF8StringEncoding]];
              [formDataM appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
              [formDataM appendData:[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"HQ_0005" ofType:@"jpg"]]];
              [formDataM appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
      
              // 添加文本
      
              [formDataM appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
              [formDataM appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; 
                                                                                 name=\"%@\"\r\n\r\n%@\r\n", @"username", @"qian"] 
                                                                             dataUsingEncoding:NSUTF8StringEncoding]];
      
              // 添加結束分隔符
      
              [formDataM appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
      
          [[[NSURLSession sharedSession] uploadTaskWithRequest:request 
                                                      fromData:formDataM 
                                             completionHandler:^(NSData * _Nullable data, 
                                                          NSURLResponse * _Nullable response, 
                                                                NSError * _Nullable error) {
      
              if (error != nil || data == nil) return;
      
              id result = [NSJSONSerialization JSONObjectWithData:data options:0 error:NULL];
              [self refreshUI:result];    
          }] resume];
    • 多文件上傳封裝

      • 文件數據封裝使用到第三方框架 QExtension,具體實現代碼見 GitHub 源碼 QExtension
      // NSData+FormData.m
              。。。。。
      
          // 設置上傳的文件數據
      
              // 指定文件數據方式
      
              NSData *filedata1 = [[NSData alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"HQ_0003" ofType:@"jpg"]];
              NSData *filedata2 = [[NSData alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"HQ_0005" ofType:@"jpg"]];
      
              NSData *formData = [NSData q_formDataWithRequest:request 
                                                     fileDatas:@[filedata1, filedata2] 
                                                          name:@"userfile[]" 
                                                     fileNames:@[@"test1.jpg", @"test2.jpg"]
                                                     mimeTypes:@[@"image/jpeg", [NSNull null]]];
      
              NSData *formData = [NSData q_formDataWithRequest:request texts:@[@"qian"] 
                                                     textNames:@[@"username"] 
                                                     fileDatas:@[filedata1, filedata2] 
                                                          name:@"userfile[]"
                                                     fileNames:@[@"test1.jpg", @"test2.jpg"] 
                                                     mimeTypes:@[@"image/jpeg", [NSNull null]]];
      
              // 指定文件路徑方式
      
              NSURL *fileURL1 = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"HQ_0003" ofType:@"jpg"]];
              NSURL *fileURL2 = [NSURL URLWithString:[[NSBundle mainBundle] pathForResource:@"HQ_0005" ofType:@"jpg"]];
      
              NSData *formData = [NSData q_formDataWithRequest:request 
                                                      fileURLs:@[fileURL1, fileURL2] 
                                                          name:@"userfile[]" 
                                                     fileNames:@[@"test1.jpg", [NSNull null]]
                                                     mimeTypes:@[@"image/jpeg", [NSNull null]]];
      
              NSData *formData = [NSData q_formDataWithRequest:request texts:@[@"qian"] 
                                                     textNames:@[@"username"] 
                                                      fileURLs:@[fileURL1, fileURL2] 
                                                          name:@"userfile[]" 
                                                     fileNames:@[@"test1.jpg", [NSNull null]] 
                                                     mimeTypes:@[@"image/jpeg", [NSNull null]]];

八、文件下載設置

  • Objective-C

    • 獲取文件信息

      // 設置網絡接口
          NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/download/file/minion_01.mp4"];
      
          // 建立網絡請求
          NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
          request.HTTPMethod = @"HEAD";
      
          [[[NSURLSession sharedSession] dataTaskWithRequest:request 
                                           completionHandler:^(NSData * _Nullable data, 
                                                        NSURLResponse * _Nullable response, 
                                                              NSError * _Nullable error) {
      
              if (error != nil || data == nil) return;
      
              NSLog(@"要下載文件的長度 %tu", response.expectedContentLength);
      
          }] resume];
    • 基本下載

      // 設置請求路徑
          NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/download/file/minion_01.mp4"];
      
          // 建立請求對象
          NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
      
          // 建立會話對象
          NSURLSession *urlSession = [NSURLSession sharedSession];
      
          NSURLSessionDownloadTask *urlSessionDownloadTask = [urlSession downloadTaskWithRequest:urlRequest 
                                                                               completionHandler:^(NSURL * _Nullable location, 
                                                                                           NSURLResponse * _Nullable response, 
                                                                                                 NSError * _Nullable error) {
      
              if (error == nil) {
      
                  // 設置下載的文件存儲路徑
                  NSString *documentsDirPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0] 
                                                   stringByAppendingPathComponent:response.suggestedFilename];
      
                  // 處理下載的數據
                  [[NSFileManager defaultManager] copyItemAtPath:location.path toPath:documentsDirPath error:nil];
              }
          }];
      
          // 執行任務
          [urlSessionDownloadTask resume];

九、文件存儲服務器 WebDav 操做

  • Objective-C

    • GET 請求

      // 設置文件位置
          NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/uploads/123.png"];
      
          [[[NSURLSession sharedSession] downloadTaskWithURL:url 
                                           completionHandler:^(NSURL * _Nullable location, 
                                                       NSURLResponse * _Nullable response, 
                                                             NSError * _Nullable error) {
      
              // 將下載的文件讀取到二進制數據
              NSData *data = [NSData dataWithContentsOfURL:location];
      
              dispatch_async(dispatch_get_main_queue(), ^{
      
                  // 若是顯示比較大的圖片,NSURLSession 能夠利用
                  self.iconView.image = [UIImage imageWithData:data];
              });
      
              // 磁盤緩存直接下載到本地,不會形成內存佔用太大
      
          }] resume];
    • PUT 請求

      // 本地要上傳的文件
          NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"minion.mp4" withExtension:nil];
      
          // 123.mp4 保存到服務器的文件名
          NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/uploads/123.mp4"];
      
          // PUT 文件上傳,以文件的方式直接寫入到 WebDav 服務器中
          NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
          urlRequest.HTTPMethod = @"PUT";
      
          // 服務器驗證,用戶訪問名和密碼
          [urlRequest setValue:[@"admin:adminpasswd" q_basic64AuthEncode] forHTTPHeaderField:@"Authorization"];       
      
          [[[NSURLSession sharedSession] uploadTaskWithRequest:urlRequest 
                                                      fromFile:fileURL 
                                             completionHandler:^(NSData * _Nullable data, 
                                                          NSURLResponse * _Nullable response, 
                                                                NSError * _Nullable error) {
      
              NSLog(@"%@ %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding], response);
      
          }] resume];
    • DELETE 請求

      // 要刪除的文件完成路徑
          NSURL *url = [NSURL URLWithString:@"http://192.168.88.200/uploads/123.mp4"];
      
          // DELETE 文件刪除
          NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url];
          urlRequest.HTTPMethod = @"DELETE";
      
          // 服務器驗證,用戶訪問名和密碼
          [urlRequest setValue:[@"admin:adminpasswd" q_basic64AuthEncode] forHTTPHeaderField:@"Authorization"];
      
          [[[NSURLSession sharedSession] dataTaskWithRequest:urlRequest 
                                           completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
      
              NSLog(@"%@ %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding], response);
      
          }] resume];
相關文章
相關標籤/搜索