这篇文章是投稿文章,原来HTTP是个老话题了,在项目中我们经常需要向服务器发送POST或者GET请求,但是对HTTP的理解不要局限对此。千里之行,始于足下。越往前走,基本原理就应该理解得透彻、全面。仅使用ASIHttpRequest或AFNetWorking传递参数来发送请求是不够的。这篇文章就是带你全方位回顾一下HTTP。从本文中你能获得什么:一个完整的HTTP请求和响应所包含的必要元素HTTP不同版本的区别HTTP、Socket、TCP的区别(容易混用)1.HTTP协议HTTP本质上是一种协议,全称是HypertextTransferProtocol,超文本传输??协议。从名字就可以看出,这个协议是用来规定客户端和服务器之间的传输规则的,传输的内容不限于文本(实际上可以传输任何类型的数据)。Figure1.1TransmissionDiagram.png二、HTTPRequest和Response的内容当我们向服务器发送HTTP请求时,我们发送了什么?我们来看一个POST请求的示例图:图2.1HTTP_POST请求example.png注:本文使用Paw模拟发送HTTP请求,使用Charles抓包。Charles选择“Request”和“Raw”选项,查看请求的全部内容上面的示例图其实包含了一个HTTP请求的几个基本要素:请求行、请求头(headerField)、请求体(body);同样,响应也有状态行、响应头和实体内容。接下来我们一一展开。1、请求行请求行包含请求方法(Method)、请求的统一资源标识符(URI)、HTTP版本号,如图2.1***行:图2.2Requestline.png请求方法为熟悉的POST、GET、HEAD、PUT等URI是URL中去掉Host后的剩余部分,即资源在本地服务器上的路径HTTP版本号。目前主流版本为1.1(1999年开始),最新版本为2.0(2015年5月发布)。下面将展开不同版本之间的区别。2.请求头请求头主要存放了客户端要给服务器的附加信息。下图中加框部分为请求头:图2.3Requestheader.pngHTTP请求在iOS中使用NSURLRequest和NSMutableRequest表示;HTTP响应由NSHTTPURLResponse表示。Host:目标服务器的网络地址Accept:让服务器知道客户端可以接收的数据类型,如text/html*/*Content-Type:body中的数据类型,如application/json;charset=UTF-8Accept-Language:客户端的语言环境,如zh-cnAccept-Encoding:客户端支持的数据压缩格式,如gzipUser-Agent:客户端的软件环境,我们可以将此字段更改为我们客户端的名称,例如QQ音乐v1.11,例如浏览器Mozilla/5.0(Macintosh;IntelMacOSX10_10_***ppleWebKit/600.8.9(KHTML,如Gecko)Maxthon/4.5。2Connection:keep-alive,该字段从HTTP1.1开始就有,用于告诉服务器这是一个持久连接,“请不要在服务器发送响应后立即断开TCP连接”。关于这个的更多解释字段会在后面的HTTP版本介绍中展开Content-Length:body的长度,如果body为空,则该字段值为0,该字段一般只在POST请求中才有。body的请求bodyPOST请求也可能为空,因此POST中的Content-Length也可能为0Cookie:Therec订单的用户信息存储在本地用户数据中。如果有的话,它会自动附加。值得一提的是,当你在iOS中发送任意请求时,NSURLRequest会自动记录你在访问的URL上设置的cookie。在iOS中以NSHTTPCookieStorage为代表,是一个单例。通过NSHTTPCookieStorage*cookieJar=[NSHTTPCookieStoragesharedHTTPCookieStorage];for(NSHTTPCookie*cookiein[cookieJarcookies]){NSLog(@"%@",cookie);}可以得到当前自动保存的所有cookie。如果你对cookies的操作感兴趣,请看这篇关于在iOS中HTTP请求中使用cookies的文章。以上就是我们在日常开发中经常遇到的请求头。其实还有其他的字段,限于篇幅不能一一列举。如果您想了解所有请求标头,请在此处查看请求标头和响应标头列表。那么如何在iOS中设置和添加这些字段呢?可以使用-[NSMutableURLRequestaddValue:forHTTPHeaderField:]方法获取当前请求中已经设置的字段。您可以使用-[NSURLRequestallHTTPHeaderFields]。也就是说我们可以通过上面的接口自定义我们需要的请求头,但是有些字段是不能改的。我们看一下iOS的描述:图2.4iOS请求头接口description.png从文档中我们可以看到,在iOS中头域AuthorizationConnectionHostWWW-Authenticate应该是没有变化的。3、请求体确实需要向服务器发送数据。POST-multipart上传请求中,请求体为上传文件的二进制NSData类型数据;GET请求中,请求体为空;在普通的POST请求中,请求体是一些表单数据。在iOS中,一般用NSURLRequest和NSMutableURLRequest的HTTPBody属性表示,添加body使用-[NSMutableURLRequestsetHTTPBody:]。4、响应状态行状态行是服务器返回给客户端的状态信息,包括HTTP版本号、状态码、状态码对应的英文名称。下面是一个典型的正确状态行:HTTP/1.1200OK这部分需要讲一下错误码。其实HTTP请求错误码按照错误码的第一位从左到右大致可以分为以下几类:1XX:信息提示。不表示成功或失败,表示暂时响应,比如100表示??继续,101表示切换协议2XX:成功3XX:重定向4XX:客户端错误,很可能是客户端有问题,比如kindandlovely404表示找不到文件,说明你的URI有问题,服务器机器上的目录下没有这个文件;414URI太长5XX:服务器错误,如504网关超时错误码不用记,如果有错误,查看对应错误码的含义即可。但是知道了上面的分类会帮助你在第一时间做出一个大概的判断,至少你可以知道是服务端还是客户端。5.响应头和响应实体与请求部分没有太大区别。响应标头的字段略有不同。响应标头中的标头字段也移动到请求标头和响应标头的列表中。3、HTTP版本介绍这里我简单的把HTTP版本分为三类:1.1之前,1.1,2.0。我将介绍这三类的主要区别:在HTTP1.1之前,不支持持久连接。服务器向客户端发送响应后,会立即断开TCP连接。没有请求头和响应头。客户端的前后台请求是同步的。下一个请求必须等待上一个请求得到服务器的响应才能发送,类似于多线程的同步机制。与1.1之前的版本相比,HTTP1.1(主流版本)做了以下性能改进:增加请求头和响应头;支持持久连接。客户端通过在请求头中指定Connection为keep-alive,告诉服务端不要在完成响应后立即释放连接。HTTP基于TCP。在HTTP1.1中,一个TCP连接可以处理多个HTTP请求。客户端的不同请求是异步的。下一个请求不用等到上一个请求回来,而是可以不断的发送请求,有点类似于多线程的异步处理。HTTP2.0基于向后兼容的原则。1.1版的一些功能在2.0版中可用,并且还使用了相同的API。但是2.0只会用于httpsurl。由于2.0的普及还需要很长时间,这里就不展开了。更多新特性,请参考本文。让我们重点关注当前版本1.1中所做的一些更改。支持持久连接有什么好处?HTTP基于TCP连接。如果连接频繁的开始然后断开,会在TCP的三次握手和四次握手上耗费大量的资源,效率低下。以请求网页为例,我们知道html网页上的图片资源并没有直接嵌入到网页中,只是提供了url,图片还需要额外发送一个HTTP请求才能下载。一个网页从请求到最终加载到本地,往往需要经过HTTP请求。在1.1版本之前,请求一个网页需要多次“握手-挥手”过程,而且每次连接都是相互独立的;而1.1及更高版本只需要至少一次。然后是异步请求。它的好处是指多线程异步处理,这里就不展开了。以上特征可以用图2.3来表示:图3.1AsynchronousRequest.jpg可以看出:1.N个请求只建立一个TCP连接,2.N个请求是连续异步发送的。四、HTTP、Socket、TCP的区别这三个概念经常被人提起,也是比较容易混淆的概念。在回顾之前,我们先看一下这三者在TCP/IP协议族中的位置关系:图4.1层次关系.pngHTTP是应用层协议,更靠近客户端;TCP是传输层协议;从层抽象出来的抽象层本质上是一个接口。所以本质上,三者还是很容易区分的。即便如此,有时您可能会感到困惑,HTTP连接、TCP连接和套接字连接有什么区别?好了,如果上面的解释还是不够清楚,我们继续往下看。1.TCP连接和HTTP连接的区别上面说过,HTTP是建立在TCP基础上的。客户端向服务器发送HTTP请求时,第一步是与服务器建立TCP连接,即先握手三次,“HelloHellohello”。从HTTP1.1开始支持持久连接,即一个TCP连接可以发送多个HTTP请求。总结:HTTP是基于TCP2的,TCP连接和Socket连接的区别我们在图4.1中提到,socket层只是在TCP/UDP传输层上做了一个抽象的接口层,所以一个socket连接可以基于连接,或者它可能基于UDP。基于TCP协议的socket连接也需要通过三次握手建立连接,是可靠的;基于UDP协议的socket连接不需要建立连接的过程,但是对方能不能收到就会发送给对方,不可靠。通讯IM就是后者。总结:Socket也是基于TCP3,HTTP连接和Socket连接的区别。区分这两个概念更有意义。毕竟TCP是看不见摸不着的,HTTP和Socket都可以用。HTTP是短连接,Socket(基于TCP协议)是长连接。HTTP1.1虽然开始支持持久连接,但仍然不能保证永远在线。一旦通过TCP三次握手建立了Socket连接,除非有一方主动断开连接,否则连接状态保持不变。HTTP连接服务器不能主动发送消息,Socket连接双方的请求发送顺序是有限制的。这一点比较重要,因为这将决定两者分别适用于哪些场景。HTTP采用“请求-响应”机制。在客户端向服务器发送消息之前,服务器无法将消息推送给客户端。必须满足客户端先发送消息,服务端再回复。Socket以点对点的方式连接双方,一方可以随时调用另一方。4、问题来了:什么时候用HTTP,什么时候用socket?提出这个问题是很自然的。当您收到与另一方的网络通信需求时,您自然会考虑是使用HTTP还是Socket。使用HTTP时:双方无需一直保持连接,如获取客户端资源、上传文件等使用Socket时:大部分即时通讯应用(QQ、微信)、聊天室、AppleAPNs等.在iOS中,一般使用原生的NSURLConnection、NSURLSession或者开源的AFNetWorking(推荐)、ASIHttpRequest(更新)。对于Socket连接,我主要使用robbiehanson的CocoaAsyncSocket(XMPPFramework也是他手上的)。5.结束以上是HTTP相关概念的复习,适合菜鸟和有经验的同学一起复习。欢迎大家留言,如果写错了,欢迎指出。
