iOS开发 HTTP协议详解

HTTP属于老话题了,在项目中我们经常需要往服务端发POST或者GET请求,但是对于HTTP的了解不应只局限于此。千里之行,始于足下。越想走的远,基本原理就应该了解的透彻全面一些,仅仅停留在使用ASIHttpRequest或者AFNetWorking传个参数发个请求的程度上是不够的。这篇文章就是带你全方面回顾一下HTTP。

通过本文你能收获哪些内容:

  • 完整HTTP请求与响应包含的必要元素
  • HTTP不同版本之间的差异
  • HTTP、Socket、TCP的区别(易混)

一、HTTP协议
HTTP本质上是一种协议,全称是Hypertext Transfer Protocol,即超文本传输协议。从名字上可以看出该协议用于规定客户端与服务端之间的传输规则,所传输的内容不局限于文本(其实可以传输任意类型的数据)。
这里写图片描述
二、HTTP请求与响应的内容
当我们往服务端发送一条HTTP请求时都发送了哪些东西过去呢?
先看一个POST请求的示例图:
这里写图片描述
注:本文使用Paw来模拟发送HTTP请求,使用Charles抓包,Charles选中”Request”以及”Raw”选项就可以看到请求的全部内容

以上示例图中其实已经包含了一个HTTP请求所必备的几大要素:请求行、请求头(headerField)、请求体(body);同理,响应也有状态行、响应头、实体内容。接下来我们逐个展开。

  1. 请求行

请求行包含请求方法(Method)、请求统一资源标识符(URI)、HTTP版本号,如图2.1第一行所示:
这里写图片描述
请求方法就是我们所熟悉的POSTGETHEADPUT
URI就是URL中排除掉Host剩下的部分,也就是资源在服务器本地上的路径
HTTP版本号,目前主流的版本是1.1(1999年开始采用),最新的版本是2.0(2015年5月发布)。不同版本之间差异下面会再展开
2、请求头
请求头主要存放对客户端想给服务端的附加信息,下图框框的部分就是请求头:
这里写图片描述
HTTP请求在iOS中用NSURLRequest与NSMutableRequest表示;HTTP响应用NSHTTPURLResponse表示。

  • Host: 目标服务器的网络地址
  • Accept: 让服务端知道客户端所能接收的数据类型,如text/html*/*
  • Content-Type: body中的数据类型,如application/json; charset=UTF-8
  • Accept-Language: 客户端的语言环境,如zh-cn
  • Accept-Encoding: 客户端支持的数据压缩格式,如gzip
  • User-Agent: 客户端的软件环境,我们可以更改该字段为自己客户端的名字,比如QQ music
    v1.11,比如浏览器Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5)
    AppleWebKit/600.8.9 (KHTML, like Gecko) Maxthon/4.5.2
  • Connection: keep-alive,该字段是从HTTP
    1.1才开始有的,用来告诉服务端这是一个持久连接,“请服务端不要在发出响应后立即断开TCP连接”。关于该字段的更多解释将在后面的HTTP版本简介中展开。
  • Content-Length: body的长度,如果body为空则该字段值为0。该字段一般在POST请求中才会有。

    POST请求的body请求体也有可能是空的,因此POST中Content-Length也有可能为0

  • Cookie: 记录者用户信息的保存在本地的用户数据,如果有会被自动附上
    值得一提的是,在iOS中当你发送一个任意请求时,不管你愿不愿意,NSURLRequest都会自动帮你记录你所访问的URL上设置的cookie。在iOS中用NSHTTPCookieStorage表示,是一个单例。通过NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage]; for (NSHTTPCookie *cookie in [cookieJar cookies]) { NSLog(@”%@”, cookie); }可以获取目前被自动保存的所有cookie。对cookie的操作感兴趣的请移步IOS中http请求使用cookie这篇文章。
    以上就是我们日常开发中比较经常遇到的请求头,其实还有其他的field,但篇幅所限无法一一列出,想了解所有请求头请看这里请求头响应头列表。那在iOS中如何设置添加这些field呢?可以使用-[NSMutableURLRequest addValue: forHTTPHeaderField:]方法,获取当前请求已经设置的field可以用-[NSURLRequest allHTTPHeaderFields]。也就是我们可以通过以上接口定制我们所需要的请求头,但是有些field是不能改的,我们看一下iOS的描述:
    这里写图片描述
    从文档中我们可以看到,在iOS中不应当对AuthorizationConnectionHostWWW-Authenticate这几个header field做更改。
    3、请求体
    真正需要发给服务端的数据,在使用POST-multipart上传请求中请求体就是上传文件的二进制NSData类型数据;在GET请求中请求体为空;在普通的POST请求中请求体就是一些表单数据。在iOS中一般用NSURLRequest与NSMutableURLRequest的HTTPBody属性表示,添加body用-[NSMutableURLRequest setHTTPBody:]。
    4、响应状态行
    状态行是服务端返回给客户端的状态信息,包含HTTP版本号、状态码、状态码对应的英文名称。
    以下就是典型的正确状态行:

 HTTP/1.1 200 OK

这个部分需要讲的是错误码。事实上HTTP请求错误码可以根据错误码从左往右第一个数字大致分为以下几类:

  • 1XX:信息提示。不代表成功或者失败,表示临时响应,比如100表示继续,101表示切换协议
  • 2XX: 成功
  • 3XX: 重定向
  • 4XX:客户端错误,很有可能是客户端发生问题,如亲切可爱的404表示未找到文件,说明你的URI是有问题的,服务器机子上该目录是没有该文件的;414URI太长
  • 5XX: 服务器错误,比如504网关超时

错误码是不用去记的,出错了再查对应的错误码含义就行。但是知道上面的分类有助于第一时间做出大体的判断,起码你能清楚是服务端还是客户端的原因。
5、响应头与响应实体
这部分与请求部分差异不大,响应头的字field会有稍许不同,响应头中的header field同样移步请求头响应头列表
三、HTTP版本简介
这里我把HTTP版本简单分为三类:1.1之前,1.1,2.0,针对这三类做个主要差异的介绍:
HTTP 1.1之前
- 不支持持久连接。一旦服务器对客户端发出响应就立即断开TCP连接
- 无请求头跟响应头
- 客户端的前后请求是同步的。下一个请求必须等上一个请求从服务端拿到响应后才能发出,有点类似多线程的同步机制。
HTTP 1.1(主流版本)
与1.1之前的版本相比,做了以下性能上的提升
- 增加请求头跟响应头
- 支持持久连接。客户端通过请求头中指定Connection为keep-alive告知服务端不要在完成响应后立即释放连接。HTTP是基于TCP的,在HTTP 1.1中一次TCP连接可以处理多次HTTP请求
- 客户端不同请求之间是异步的。下一个请求不必等到上一个请求回来后再发出,而可以连续发出请求,有点类似多线程的异步处理。
HTTP 2.0
本着向下兼容的原则,1.1版本有的特性2.0都具备,也使用相同的API。但是2.0将只用于https网址。由于2.0的普及还需要比较长的一段时间,这里不展开,更多新特性请参考这篇文章

我们重点关注一下当前1.1版本所做几点改变。支持持久连接有什么好处呢?HTTP是基于TCP连接的,如果连接被频繁地启动然后断开就会花费很多资源在TCP三次握手以及四次挥手上,效率低下。以请求一个网页为例,我们知道,一个html网页上的图片资源并不是直接嵌入在网页上,而只是提供url,图片仍需要额外发HTTP 请求去下载。一个网页从请求到最终加载到本地往往需要经过过个HTTP请求。在1.1版本之前请求一个网页就需要发生多次”握手-挥手”的过程,每次连接之间相互独立;而1.1及之后的版本最少只需要一次就够。

再来就是请求异步,其好处参考多线程异步处理,在此不展开。

以上特性可以用图2.3表示:
这里写图片描述

我们可以看到:1、N次请求其实只建立了1次TCP连接,2、N次请求连续异步发出。

四、HTTP、Socket、TCP的区别
这三个概念经常被谈到,也是比较容易被混掉的概念。在回顾之前我们先看一下这三者在TCP/IP协议族中的位置关系:
这里写图片描述
HTTP是应用层的协议,更靠近用户端;TCP是传输层的协议;而socket是从传输层上抽象出来的一个抽象层,本质是接口。所以本质上三种还是很好区分的。尽管如此,有时候你可能会懵逼,HTTP连接、TCP连接、socket连接有什么区别?好吧,如果上面的图解释的还是不够清楚的话,我们继续往下看。

1、TCP连接与HTTP连接的区别
上文提过,HTTP是基于TCP的,客户端往服务端发送一个HTTP请求时第一步就是要建立与服务端的TCP连接,也就是先三次握手,“你好,你好,你好”。从HTTP 1.1开始支持持久连接,也就是一次TCP连接可以发送多次的HTTP请求。

小总结:HTTP基于TCP
2、TCP连接与Socket连接的区别
在图4.1中我们提到,socket层只是在TCP/UDP传输层上做的一个抽象接口层,因此一个socket连接可以基于TCP,也有可能基于UDP。基于TCP协议的socket连接同样需要通过三次握手建立连接,是可靠的;基于UDP协议的socket连接不需要建立连接的过程,不过对方能不能收到都会发送过去,是不可靠的,大多数的即时通讯IM都是后者。

小总结:Socket也可以基于TCP
3、HTTP连接与Socket连接的区别
区分这两个概念是比较有意义的,毕竟TCP看不见摸不着,HTTP与Socket是实实在在能用到的。

  • HTTP是短连接,Socket(基于TCP协议的)是长连接。尽管HTTP1.1开始支持持久连接,但仍无法保证始终连接。而Socket连接一旦建立TCP三次握手,除非一方主动断开,否则连接状态一直保持。
  • HTTP连接服务端无法主动发消息,Socket连接双方请求的发送先后限制。这点就比较重要了,因为它将决定二者分别适合应用在什么场景下。HTTP采用“请求-响应”机制,在客户端还没发送消息给服务端前,服务端无法推送消息给客户端。必须满足客户端发送消息在前,服务端回复在后。Socket连接双方类似peer2peer的关系,一方随时可以向另一方喊话。

4、问题来了:什么时候该用HTTP,什么时候该用socket
这个问题的提出是很自然而然的。当你接到一个与另一方的网络通讯需求,自然会考虑用HTTP还是用Socket。

用HTTP的情况:双方不需要时刻保持连接在线,比如客户端资源的获取、文件上传等

用Socket的情况:大部分即时通讯应用(QQ、微信)、聊天室、苹果APNs等

在iOS中,发HTTP请求一般用原生的NSURLConnection、NSURLSession或者开源的AFNetWorking(推荐)、ASIHttpRequest(已停止更新)。连接Socket连接我用的比较多是robbiehanson大神的CocoaAsyncSocket
(XMPPFramework也是出自他手)。

五、The end
以上就是关于HTTP相关概念的回顾,适合菜鸟也适合有经验同学一起回顾。

欢迎留言,如果写的不对的地方还请不吝指出。

阅读更多
文章标签: http协议
想对作者说点什么? 我来说一句

HTTP协议详解.pdf

2017年11月18日 194KB 下载

HTTP协议详解 pdf文档

2011年06月08日 189KB 下载

HTTP协议详解 无状态协议

2009年11月13日 46KB 下载

HTTP协议详解.doc

2009年03月04日 80KB 下载

HTTP协议详解

2015年12月23日 4KB 下载

没有更多推荐了,返回首页

不良信息举报

iOS开发 HTTP协议详解

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭