iOS - NetRequest 网络数据请求

1、网络请求

1.1 网络通讯三要素

  • 1、IP 地址(主机名):

    • 网络中设备的唯一标示。不易记忆,可以用主机名(域名)。

    • 1) IP V4:

      • 0~255.0~255.0~255.0~255 ,共有 2^8^4 = 2^32 = 42 亿。
    • 2) 本地回环地址:

      • 每台机器都有自己的本地回环地址,ip 为 127.0.0.1 ,主机名为 localhost。如果 127.0.0.1 ping 不通,则网卡不正常。

      • 本地 hosts 文件修改,终端:

        • $ cd /etc
        • $ sudo vim hosts
        • $ 输入密码进入 hosts 文件编辑界面
        • $ 将光标移动到指定位置
          - 英文输入模式下按 i 键进入编辑状态,
          - 英文输入模式下按 esc 键进入命令状态,
          - 在命令状态下输入 :wq 回车,保存退出 hosts 文件。
  • 2、端口号:

    • 用于标示进程的逻辑地址,不同进程的标示。
    • 有效端口为 0 ~ 65535,其中 0 ~ 1024 由系统使用或者保留端口,开发中不要使用 1024 以下的端口。

    • 1) Netcat 的使用:

      • Netcat 是 Mac 终端下用于调试和检查网络的工具包,可用于创建 TCP/IP 连接。
      • 终端:$ nc -lk 12345,开启监听,终端将始终监听本地计算机 12345 端口的数据。
  • 3、传输协议(通讯的规则):

    • 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 个步骤:

  • 1、建立 TCP 连接

    • 在 HTTP 工作开始之前,Web 浏览器首先要通过网络与 Web 服务器建立连接,该连接是通过 TCP 来完成的,该协议与 IP 协议共同构建 Internet,即著名的 TCP/IP 协议族,因此Internet 又被称作是 TCP/IP 网络。HTTP 是比 TCP 更高层次的应用层协议,根据规则,只有低层协议建立之后才能进行更层协议的连接,因此,首先要建立 TCP 连接,一般 TCP 连接的端口号是 80。
  • 2、Web 浏览器向 Web 服务器发送请求命令

    • 一旦建立了 TCP 连接,Web 浏览器就会向 Web 服务器发送请求命令。例如:GET /sample/hello.jsp HTTP/1.1
  • 3、Web 浏览器发送请求头信息

    • 浏览器发送其请求命令之后,还要以头信息的形式向 Web 服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。
  • 4、Web 服务器应答

    • 客户机向服务器发出请求后,服务器会给客户机回送应答,HTTP/1.1 200 OK,应答的第一部分是协议的版本号和应答状态码。
  • 5、Web 服务器发送应答头信息

    • 正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。
  • 6、Web 服务器向浏览器发送数据

    • Web 服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以 Content-Type 应答头信息所描述的格式发送用户所请求的实际数据。
  • 7、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             // 请求体
  • 1、请求行:

    • 请求的第一行,其组成为:请求方法 请求路径 协议/版本

      • 请求行 :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
  • 2、请求头:

    • 请求头包含许多有关客户端环境和请求体的有用信息。例如,请求头可以声明浏览器所用的语言,请求体的长度等。当我们打开一个网页时,浏览器要向网站服务器发送一个 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 服务器。
  • 3、请求体:

    • 请求头和请求体之间是一个空行,这个行非常重要,它表示请求头已经结束,接下来的是请求体。请求体中可以包含客户提交的查询字符串信息。如:

      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>
  • 1、状态行:

    • 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 :请求失败,请求所希望得到的资源未被在服务器上发现。
  • 2、响应头:

    • 响应头也和请求头一样包含许多有用的信息,例如服务器类型、日期时间、内容类型和长度等:

          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
  • 3、响应正文:

    • 响应正文就是服务器返回的 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。

  • 同步和异步网络请求的区别:

    • 1、同步网络请求,主线程负责数据的、视图的初始化和界面的展示等。同步网络数据请求也在主线程中进行,如果耗时较长,在数据请求完毕之前,其他线程一律不响应,会对主线程造成阻塞,造成程序假死现象,用 户体验极差。

    • 2、异步网络请求,主线程负责数据的、视图的初始化和界面的展示等。异步网络数据请求的时候,会在主线程之外单独开辟一个线程去处理网络请求,主线程依然处于可交互状态,程序运行流畅。

    • 许多开发者都会认为同步的连接将会堵塞主线程,其实这种观点是错误的。一个同步的连接是会阻塞调用它的线程。如果你在主线程中创建一个同步连接,没错,主线程会阻塞。但是如果你并不是从主线程开启的一个同步的连接,它将会类似异步的连接一样。因此这种情况并不会堵塞你的主线程。事实上,同步和异步的主要区别就是运行 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 网络请求基本设置

  • 1、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
      propertyurldescription
      URLhttps://swiftinaction.com/example?section=5&ie=utf-8URL 路径
      schemehttps协议,http、https、ftp、file(本地文件)、data(数据)
      hostswiftinaction.com主机,可以利用 Reachability 框架判断能否连接到要访问的主机
      portnil端口,nil 使用默认端口 80
      pathexample路径,不包含协议头/主机地址/端口/参数
      parametersnil参数,变量名和变量值成对出现,使用 = 分隔,多个参数使用 & 连接
      querysection=5&ie=utf-8查询参数
      fragmentnil信息片段
      absoluteStringhttps://swiftinaction.com/example?section=5&ie=utf-8完整的字符串
      resourceSpecifier//swiftinaction.com/example?section=5&ie=utf-8不包含协议头的剩余内容
      baseURLnil参照路径,默认为 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 替换成此方法,要根据是否是解码来区分。
  • 2、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) 请求体:

      • 客户端发给服务器的具体数据。
  • 3、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) 响应体:

      • 服务器返回给客户端的具体二进制数据。
  • 4、请求结果处理:

    • 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 中声明,倒退回不安全的网络请求。

  • 1、关闭强制 https 请求:

    • 设置如下,添加 App Transport Security Settings 项,在其下添加 Allows Arbitrary Loads 并设置值为 YES。

      NetRequest1

    • 设置代码如下:

          <key>NSAppTransportSecurity</key>
          <dict>
              <key>NSAllowsArbitraryLoads</key>
              <true/>
          </dict>
  • 2、设置 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 常用方法

  • 1、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 的内容粘贴出来。
  • 2、二进制数据 编码表单数据

    • 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/mpegmp3 文件
          video/mp4mp4 文件
          text/htmlhtml 文本文件
          text/plaintxt 文本文件
          text/rtfrtf 文本文件
          application/pdfpdf 文件
          application/jsonjson 文件
          application/octet-stream8 进制流,如果不想告诉服务器具体的文件类型,可以使用这个
      • 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。
      • 目前很多服务器不仅不限制大小,而且鼓励上传多个文件。
      • 云服务器的普及。
      • 软件商希望获得更多的用户数据。
  • 3、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 文件下载设置

  • 1、HEAD 方法:

    • HEAD 方法通常是用来在下载文件之前,获取远程服务器上的文件信息。与 GET 方法相比,同样能够拿到响应头,但是不返回数据实体,用户可以根据响应头信息,确定下一步操作。

    • 用响应头的 response.expectedContentLength 可以获取文件数据的大小。

    • 同步方法是阻塞式的,通常只有 HEAD 方法(获得的数据很少,而且后续的下载会依赖)才会使用同步方法。在截取网络数据的时候,最好使用同步方法,而且如果频率太高,需要增加延时,否则会被服务器给加入黑名单。

  • 2、文件下载方法:

    • 1) 使用 GET 数据请求方法,数据请求完成后,将数据手动写入文件中。

    • 2) 使用专门用于下载的 GET 方法,数据请求完成后,将会自动写入指定文件中。

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

    • 1) 拼接数据,统一写入磁盘
      • 问题:内存峰值可能会很高。
    • 2) 每次接收到二进制数据,都直接写入磁盘
      • NSFileHandle 文件句柄写入
      • NSOutputStream 文件流写入
  • 4、文件断点下载步骤:

    • 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"];

  • 5、文件下载设置:

    • 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];
  • 6、块代码回调:

    • 1) Block 的属性定义:

      • 如果本方法能够直接执行到 block,就不需要定义 block 属性。
      • 如果本方法不能直接执行 block,就需要定义 block 属性。
    • 2) 网络 block 回调的几个 "约定":

      • AFN/SDWebImage 等第三方框架,都是这么做的。

      • 1> 进度的回调,在异步回调
        • 进度的频率非常高,如果在某些 UI 上高频率回调进度,会造成界面卡顿。
        • 如果需要,就在主线程更新 UI,如果卡的太厉害,就想别的解决方法,如使用旋转的小菊花等。
      • 2> 成功的回调,在主线程回调
        • 成功只有一个,在主线程回调,调用方不需要考虑线程间通讯。
      • 3> 失败的回调,可以在主线程,也可以在后台线程

2、同步 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!))

3、同步 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)

4、异步 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
    
        }

5、异步 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
    
        }

6、网络请求基本设置

  • 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];

7、文件上传设置

  • 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]]];

8、文件下载设置

  • 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];                                                                                                

9、文件存储服务器 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];

转载于:https://www.cnblogs.com/QianChia/p/5762437.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值