关于http相关知识点

1.http基础

声明:本文是本人 编程小翁 原创,转载请注明。

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

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

一、HTTP协议

HTTP本质上是一种协议,全称是Hypertext Transfer Protocol,即超文本传输协议。从名字上可以看出该协议用于规定客户端与服务端之间的传输规则,所传输的内容不局限于文本(其实可以传输任意类型的数据)。


图1.1传输示意图.png

二、HTTP请求与响应的内容

当我们往服务端发送一条HTTP请求时都发送了哪些东西过去呢?
先看一个POST请求的示例图:


图2.1 HTTP_POST请求示例.png

注:本文使用Paw来模拟发送HTTP请求,使用Charles抓包,Charles选中"Request"以及"Raw"选项就可以看到请求的全部内容

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

1、请求行

请求行包含请求方法(Method)、请求统一资源标识符(URI)、HTTP版本号,如图2.1第一行所示:


图2.2 请求行.png
  • 请求方法就是我们所熟悉的POST、GET、HEAD、PUT等
  • URI就是URL中排除掉Host剩下的部分,也就是资源在服务器本地上的路径
  • HTTP版本号,目前主流的版本是1.1(1999年开始采用),最新的版本是2.0(2015年5月发布)。不同版本之间差异下面会再展开

2、请求头

请求头主要存放对客户端想给服务端的附加信息,下图框框的部分就是请求头:


图2.3 请求头.png


HTTP请求在iOS中用NSURLRequestNSMutableRequest表示;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的描述:


图2.4 iOS请求头接口描述.png

从文档中我们可以看到,在iOS中不应当对Authorization Connection Host WWW-Authenticate这几个header field做更改。

3、请求体

真正需要发给服务端的数据,在使用POST-multipart上传请求中请求体就是上传文件的二进制NSData类型数据;在GET请求中请求体为空;在普通的POST请求中请求体就是一些表单数据。在iOS中一般用NSURLRequestNSMutableURLRequestHTTPBody属性表示,添加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之前的版本相比,做了以下性能上的提升

  • 增加请求头跟响应头
  • 支持持久连接。客户端通过请求头中指定Connectionkeep-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表示:


图3.1 异步请求.jpg

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

四、HTTP、Socket、TCP的区别

这三个概念经常被谈到,也是比较容易被混掉的概念。在回顾之前我们先看一下这三者在TCP/IP协议族中的位置关系:


图4.1 层次关系.png

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请求一般用原生的NSURLConnectionNSURLSession或者开源的AFNetWorking(推荐)ASIHttpRequest(已停止更新)。连接Socket连接我用的比较多是robbiehanson大神的CocoaAsyncSocket (XMPPFramework也是出自他手)。

五、The end

以上就是关于HTTP相关概念的回顾,适合菜鸟也适合有经验同学一起回顾。
欢迎留言,如果写的不对的地方还请不吝指出。




2.http状态码

一、HTTP状态码

 

如果某项请求发送到您的服务器要求显示您网站上的某个网页(例如,用户通过浏览器访问您的网页或 Googlebot 抓取网页时),服务器将会返回 HTTP 状态代码以响应请求。

 

此状态代码提供关于请求状态的信息, 告诉 Googlebot 关于您的网站和请求的网页的信息。

一些常见的状态代码包括:

  • 200 – 服务器成功返回网页
  • 404 – 请求的网页不存在
  • 503 – 服务器暂时不可用

 

下面提供 HTTP 状态代码的完整列表。 点击链接可了解详情。 您也可以访问有关 HTTP 状态代码的 W3C 网页以获得更多信息 。

 

1xx:请求收到,继续处理
2xx:操作成功收到,分析、接受
3xx:完成此请求必须进一步处理
4xx:请求包含一个错误语法或不能完成
5xx:服务器执行一个完全有效请求失败



1xx (临时响应) 
表示临时响应并需要请求者继续执行操作的状态代码。

 

 

代码 说明
100(继续)请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。
101(切换协议)请求者已要求服务器切换协议,服务器已确认并准备切换。

 

 

2xx (成功)

表示服务器成功处理了请求的状态代码。

 

 

代码 说明
200(成功)服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。 如果针对您的 robots.txt 文件显示此状态,则表示 Googlebot 已成功检索到该文件。
201(已创建)请求成功并且服务器创建了新的资源。
202(已接受)服务器已接受请求,但尚未处理。
203(非授权信息)服务器已成功处理了请求,但返回的信息可能来自另一来源。
204(无内容)服务器成功处理了请求,但没有返回任何内容。
205(重置内容)服务器成功处理了请求,但没有返回任何内容。 与 204 响应不同,此响应要求请求者重置文档视图(例如,清除表单内容以输入新内容)。
206(部分内容)服务器成功处理了部分 GET 请求。

 

 

3xx (重定向) 
要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。 Google 建议您在每次请求中使用重定向不要超过 5 次。 您可以使用网站管理员工具查看一下 Googlebot 在抓取重定向网页时是否遇到问题。 诊断 下的网 络抓取 页面列出了由于重定向错误而导致 Googlebot 无法抓取的网址。

 

 

代码 说明
300(多种选择)针对请求,服务器可执行多种操作。 服务器可根据请求者(用户代理)选择一项操作,或提供操作列表供请求者选择。
301(永久移动)请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。 您应使用此代码告诉 Googlebot 某个网页或网站已永久移动到新位置。
302(暂时移动)服 务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。 此代码与响应 GET 或 HEAD 请求的 301 代码类似,会自动将请求者转到不同的位置,但您不应使用此代码来告诉 Googlebot 某个网页或网站已经移动,因为 Googlebot 会继续抓取原有位置并编入索引。
303(查看其他位置)请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。 对于除 HEAD 之外的所有请求,服务器会自动转到其他位置。
304(未修改)自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容。如果网页自请求者上次请求后再也没有更改 过,您应当将服务器配置为返回此响应(称为 If-Modified-Since HTTP 标头)。 由于服务器可以告诉 Googlebot 自从上次抓取后网页没有更改过,因此可节省带宽和开销

305(使用代理)请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。
307(暂时重定向)服 务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。 此代码与响应 GET 和 HEAD 请求的 301 代码类似,会自动将请求者转到不同的位置,但您不应使用此代码来告诉 Googlebot 某个页面或网站已经移动,因为 Googlebot 会继续抓取原有位置并编入索引。

 

 

4xx(请求错误) 
这些状态代码表示请求可能出错,妨碍了服务器的处理。

 

 

代码 说明
400(错误请求)服务器不理解请求的语法。
401(未授权)请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。
403(禁止)服务器拒绝请求。 如果您看到 Googlebot 在尝试抓取您网站上的有效网页时收到此状态代码(可以在 Google 网站管理员工具诊 断 下的网络抓取 页面上看到此信息),可能是您的服务器或主机拒绝 Googlebot 访问。
404(未找到)服务器找不到请求的网页。 例如,如果请求服务器上不存在的网页,服务器通常会返回此代码。如果您的网站上没有 robots.txt 文件,而您在 Google 网站管理员工具”诊断”标签的 robots.txt 页 上看到此状态,那么这是正确的状态。 但是,如果您有 robots.txt 文件而又看到此状态,则说明您的 robots.txt 文件可能命名错误或位于错误的位置 (该文件应当位于顶级域名,名为 robots.txt)。

如果您看到有关 Googlebot 尝试抓取的网址的此状态(在”诊断”标签的 HTTP 错误页上),则表示 Googlebot 追踪的可能是另一个页面的无效链接(是旧链接或输入有误的链接)。

405(禁用的方法)禁用请求中指定的方法。
406(不可接受)无法使用请求的内容特性响应请求的网页。
407(需要代理授权)此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。 如果服务器返回此响应,还会指明请求者应当使用的代理。
408(请求超时)服务器等候请求时发生超时。
409(冲突)服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。 服务器在响应与前一个请求相冲突的 PUT 请求时可能会返回此代码,同时会附上两个请求的差异列表。
410(已删除)如果请求的资源已永久删除,服务器就会返回此响应。 该代码与 404(未找到)代码相似,但在资源以前存在而现在不存在的情况下,有时会用来替代 404 代码。 如果资源已永久删除,您应当使用 301 指定资源的新位置。
411(需要有效长度)服务器不接受不含有效内容长度标头字段的请求。
412(未满足前提条件)服务器未满足请求者在请求中设置的其中一个前提条件。
413(请求实体过大)服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。
414(请求的 URI 过长)请求的 URI(通常为网址)过长,服务器无法处理。
415(不支持的媒体类型)请求的格式不受请求页面的支持。
416(请求范围不符合要求)如果页面无法提供请求的范围,则服务器会返回此状态代码。
417(未满足期望要求)服务器未满足”期望”请求标头字段的要求。

 

 

5xx (服务器错误) 
这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。

 

 

代码 说明
500(服务器内部错误)服务器遇到错误,无法完成请求。
501(尚未实施)服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。
502(错误网关)服务器充当网关或代理,从上游服务器收到无效响应。
503(服务不可用)服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。
504(网关超时)服务器充当网关或代理,但没有及时从上游服务器收到请求。
505(HTTP 版本不受支持)服务器不支持请求中所用的 HTTP 协议版本。

 

 

英文版:

100:Continue
101:Switching Protocols
102:Processing

200:OK
201:Created
202:Accepted
203:Non-Authoriative Information
204:No Content
205:Reset Content
206:Partial Content
207:Multi-Status

300:Multiple Choices
301:Moved Permanently
302:Found
303:See Other
304:Not Modified
305:Use Proxy
306:(Unused)
307:Temporary Redirect

400:Bad Request
401:Unauthorized
402:Payment Granted
403:Forbidden
404:File Not Found
405:Method Not Allowed
406:Not Acceptable
407:Proxy Authentication Required
408:Request Time-out
409:Conflict
410:Gone
411:Length Required
412:Precondition Failed
413:Request Entity Too Large
414:Request-URI Too Large
415:Unsupported Media Type
416:Requested range not satisfiable
417:Expectation Failed
422:Unprocessable Entity
423:Locked
424:Failed Dependency

500:Internal Server Error
501:Not Implemented
502:Bad Gateway
503:Service Unavailable
504:Gateway Timeout
505:HTTP Version Not Supported
507:Insufficient Storage

200号状态码

220.181.32.30 - - [02/Sep/2008:00:01:23 +0800] "GET /article/0572/72570.shtml HTTP/1.1" 200 28361 "-" "Baiduspider+(+http://www.baidu.com/search/spider.htm)"

服务器日志中的200表示使用GET传递方式网页72570.shtml下载成功。即:当用户或爬虫程序向网站服务器发出浏览请求时,服务器返回 HTTP 数据流里包含某种状态码,200响应号即状态码中的一种,表示本网页被成功下载。

301号状态码

220.181.32.30 - - [02/Sep/2008:00:01:31 +0800] "GET /my/view.php?aid=14183 HTTP/1.1" 301 - "-" "Baiduspider+(+http://www.baidu.com/search/spider.htm)"

服务器日志中的301表示使用GET传递方式动态网页aid=14183成功跳转。即:当用户或爬虫程序向网站服务器发出浏览请求时,服务器返回 HTTP 数据流包含某种状态码,301 重定向即状态码中的一种,表示本网页永久性转移到另一个地址。实际操作中我们可以将多个域名指向同一个网址,这也是搜索引擎唯一认可的一种网站转向的方式。

 

 

二、404状态码

 

220.181.32.30 - - [02/Sep/2008:00:01:51 +0800] "GET /writing HTTP/1.1" 404 4459 "-" "Baiduspider+(+http://www.baidu.com/search/spider.htm)"

 

出现404状态码就证 明有URL地址的网页浏览不到。很多时候由于网站的改版,使很多旧版网站url地址失效。这是你需要建立404状态页来保证你网站通畅,能够达到一种回路 的效果。切记404状态页需要单独设计,不能直接在服务器端直接跳转回首页。否则,搜索引擎会大量抓取网站首页失误当成404页处理。

 

对HTTP404状态码的深度理解

 

HTTP 404 错误意味着链接指向的网页不存在,即原始网页的URL失效,这种情况经常会发生,很难避免,比如说:网页URL生成规则改变、网页文件更名或移动位置、导 入链接拼写错误等,导致原来的URL地址无法访问;当Web 服务器接到类似请求时,会返回一个404 状态码,告诉浏览器要请求的资源并不存在。但是,Web服务器默认的404错误页面,无论Apache还是IIS,均十分简陋、呆板且对用户不友好,无法 给用户提供必要的信息以获取更多线索,无疑这会造成用户的流失。

 

因此,很多网站均使用自定义404错误的方式以提供用户体验避免用户流失。一般而言,自定义404页面通用的做法是在页面中放置网站快速导航链接、搜索框以及网站提供的特色服务,这样可以有效的帮助用户访问站点并获取需要的信息。

HTTP404对SEO的影响

 

自 定义404错误页面是提供用户体验的很好的做法,但在应用过程中往往并未注意到对搜索引擎的影响,譬如:错误的服务器端配置导致返回“200”状态码或自 定义404错误页面使用Meta Refresh导致返回“302”状态码。正确设置的自定义404错误页面,不仅应当能够正确地显示,同时,应该返回“404”错误代码,而不是 “200”或“302”。虽然对访问的用户而言,HTTP状态码究竟是“404”还是“200”来说并没有什么区别,但对搜索引擎而言,这则是相当重要 的。


1.自定义404错误页返回“200”状态码

 

当搜索引擎蜘蛛在请求某个URL地址得到“404”状态回应时,即知道该 URL地址已经失效,便不再索引该网页,并向数据中心反馈将该URL地址表示的网页从索引数据库中删除,当然,删除过程有可能需要很长时间;而当搜索引擎 得到“200”状态回应时,则会认为该url地址是有效的,便会去索引,并会将其收录到索引数据库,这样的结果便是这两个不同的url地址具有完全相同的 内容:自定义404错误页面的内容,这会导致出现复制网页问题。对搜索引擎而言,特别是Google,不但很难获得信任指数TrustRank,也会大大 降低Google对网站质量的评定。

 

在使用Google Sitemap,当提交XML格式网站地图文件时,谷歌管理员工具会验证网站的身份以确保是网站合法的管理者。验证方式有两种:上传指定名称的html页 到网站根目录或者在网页meta区域添加一个标识身份的meta标签。通常是使用上传html网页的方式,但谷歌管理员工具却提示网站根目录下找不到这个 网页,这是一个很可怕的问题。

 

 

2.自定义404错误页使用Meta Refresh返回“302”状态码

 

常常看到许多网站的 自定义404错误页面采取类似这样的形式:首先显示一段错误信息,然后,通过Meta Refresh将页面跳转到网站首页、网页地图或其他类似页。根据具体实现方式不同,这类404页面可能返回“200”状态码,也可能返回“302”,但 不论哪种,从SEO技术角度看,均不是一种合适的选择。

 

对“200”状态的情况我们上面已经谈过,那么,当404页面返回“302”时,搜 索引擎会怎么对待呢?从理论上说,对“302”错误,搜索引擎认为该网页是存在的,只不过临时改变了地址,仍然会索引收录该页,这样,同样会出现类似于 “200”状态码时的重复文本问题;其次,以谷歌为代表的主流搜索引擎对302重定向的适用范围要求越来越严格,这类不当使用302重定向的情况存在很大 的风险。

 

确保自定义404错误页面能够返回“404”状态码

 

在自定义404错误页面设置完毕后,一定要检查一下其是不是能够正确地返回“404”状态码。可以使用Server Header检查工具,输入一个不存在网页的url,查看一下HTTP Header的返回情况,确信其返回的是“404 Not found”。

声明:本文是本人 编程小翁 原创,转载请注明。

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

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

一、HTTP协议

HTTP本质上是一种协议,全称是Hypertext Transfer Protocol,即超文本传输协议。从名字上可以看出该协议用于规定客户端与服务端之间的传输规则,所传输的内容不局限于文本(其实可以传输任意类型的数据)。


图1.1传输示意图.png

二、HTTP请求与响应的内容

当我们往服务端发送一条HTTP请求时都发送了哪些东西过去呢?
先看一个POST请求的示例图:


图2.1 HTTP_POST请求示例.png

注:本文使用Paw来模拟发送HTTP请求,使用Charles抓包,Charles选中"Request"以及"Raw"选项就可以看到请求的全部内容

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

1、请求行

请求行包含请求方法(Method)、请求统一资源标识符(URI)、HTTP版本号,如图2.1第一行所示:


图2.2 请求行.png
  • 请求方法就是我们所熟悉的POST、GET、HEAD、PUT等
  • URI就是URL中排除掉Host剩下的部分,也就是资源在服务器本地上的路径
  • HTTP版本号,目前主流的版本是1.1(1999年开始采用),最新的版本是2.0(2015年5月发布)。不同版本之间差异下面会再展开

2、请求头

请求头主要存放对客户端想给服务端的附加信息,下图框框的部分就是请求头:


图2.3 请求头.png


HTTP请求在iOS中用NSURLRequestNSMutableRequest表示;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的描述:


图2.4 iOS请求头接口描述.png

从文档中我们可以看到,在iOS中不应当对Authorization Connection Host WWW-Authenticate这几个header field做更改。

3、请求体

真正需要发给服务端的数据,在使用POST-multipart上传请求中请求体就是上传文件的二进制NSData类型数据;在GET请求中请求体为空;在普通的POST请求中请求体就是一些表单数据。在iOS中一般用NSURLRequestNSMutableURLRequestHTTPBody属性表示,添加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之前的版本相比,做了以下性能上的提升

  • 增加请求头跟响应头
  • 支持持久连接。客户端通过请求头中指定Connectionkeep-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表示:


图3.1 异步请求.jpg

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

四、HTTP、Socket、TCP的区别

这三个概念经常被谈到,也是比较容易被混掉的概念。在回顾之前我们先看一下这三者在TCP/IP协议族中的位置关系:


图4.1 层次关系.png

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请求一般用原生的NSURLConnectionNSURLSession或者开源的AFNetWorking(推荐)ASIHttpRequest(已停止更新)。连接Socket连接我用的比较多是robbiehanson大神的CocoaAsyncSocket (XMPPFramework也是出自他手)。

五、The end

以上就是关于HTTP相关概念的回顾,适合菜鸟也适合有经验同学一起回顾。
欢迎留言,如果写的不对的地方还请不吝指出。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值