Android 网络编程(http协议)

简介

  • HTTP全称是Hyper Text Transfer Protocol,翻译过来叫超文本传输协议,看起来很高端的名字,实际上他就是字面意思,就比如你想知道“HTTP协议是什么”,服务器上呢有个超文本,就姑且当他是个记事本里面记录着“HTTP协议是什么”的答案,你想要,那么服务器就和你约定好了用“顺丰快递传”,所以这就是传输超文本的协议。
  • 它是一个属于应用层的协议,什么叫应用层,简单说就是和应用进程交互 的层,想想应用里面有什么好交互的,当然是数据了,也就是说这一层解决的是如何包装数据的,还是很像快递。

特点

  1. C/S模式,快递员服务于客户。
  2. 简单:客户向服务器请求服务时,只需传送请求方法和路径。请求方法常用的有GET、HEAD、POST,每种方法规定了客户与服务器联系的类型不同。就相当于告诉快递员你的地址(路径)和你要的运输的方式(请求方法),比如我家住安卓小区你给我空运过来。。。
  3. 快速:由于HTTP协议简单,使得HTTP服务器的程序规模小,因而通信速度很快。
  4. 灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由Content-Type加以标记。
  5. 无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。但是这种方式在请求频繁的条件下,将会在建立和断开连接上花费大部分时间,所以在1.0、1.1持久连接变为了默认连接方式,有兴趣的可以自己查一下这个方式。
  6. 无状态:HTTP协议是无状态协议,简单说就是健忘、没脑子。打电话给常年在小区送快递的快递小哥:“哥,还送老地方”,小哥:“你谁呀不认识!”,挂了。。。所以无状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

URL 格式

http://host[":"port][abs_path]

如:http://blog.csdn.net:80/qijinglai
http表示要通过HTTP协议来定位网络资源;host表示合法的Internet主机域名或者IP地址;port指定一个端口号,为空则使用默认端口80;abs_path指定请求资源的URI(Web上任意的可用资源)。

Http报文

http报文可以分为请求报文和响应报文,格式大同小异。主要分为三个部分:

  1. 起始行
  2. 首部
  3. 主体

请求报文格式:

  



响应报文格式:

  



从请求报文格式和响应报文格式可以看出,两者主要在起始行上有差异。这里稍微解释一下各个标签:

 指请求方法,常用的主要是Get、 Post、Head 还有其他一些我们这里就不说了,有兴趣的可以自己查阅一下

 指协议版本,现在通常都是Http/1.1了

 请求地址

 指响应状态码, 我们熟悉的200、404等等

 原因短语,200 OK 、404 Not Found 这种后面的描述就是原因短语,通常不必太关注。

method

HTTP请求方法有8种

  1. GET:请求获取Request-URI所标识的资源
  2. POST:在Request-URI所标识的资源后附加新的数据
  3. HEAD:请求获取由Request-URI所标识的资源的响应消息报头
  4. PUT: 请求服务器存储一个资源,并用Request-URI作为其标识
  5. DELETE :请求服务器删除Request-URI所标识的资源
  6. TRACE : 请求服务器回送收到的请求信息,主要用于测试或诊断
  7. CONNECT: HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
  8. OPTIONS :请求查询服务器的性能,或者查询与资源相关的选项和需求

GET和POST的区别

两个方法之间在传输形式上有一些区别,通过Get方法发起请求时,会将请求参数拼接在request-url尾部,格式是url?param1=xxx¶m2=xxx&[…]。
我们需要知道,这样传输参数会使得参数都暴露在地址栏中。并且由于url是ASCII编码的,所以参数中如果有Unicode编码的字符,例如汉字,都会编码之后传输。另外值得注意的是,虽然http协议并没有对url长度做限制,但是一些浏览器和服务器可能会有限制,所以通过GET方法发起的请求参数不能够太长。而通过POST方法发起的请求是将参数放在请求体中的,所以不会有GET参数的这些问题。
另外一点差别就是方法本身的语义上的。GET方法通常是指从服务器获取某个URL资源,其行为可以看作是一个读操作,对同一个URL进行多次GET并不会对服务器产生什么影响。而POST方法通常是对某个URL进行添加、修改,例如一个表单提交,通常会往服务器插入一条记录。多次POST请求可能导致服务器的数据库中添加了多条记录。所以从语义上来讲,两者也是不能混为一谈的。

状态码

状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:

  • 100~199:指示信息,表示请求已接收,继续处理
  • 200~299:请求成功,表示请求已被成功接收、理解、接受
  • 300~399:重定向,要完成请求必须进行更进一步的操作
  • 400~499:客户端错误,请求有语法错误或请求无法实现
  • 500~599:服务器端错误,服务器未能实现合法的请求

常见的状态码如下:

  • 200 OK:客户端请求成功
  • 400 Bad Request:客户端请求有语法错误,不能被服务器所理解
  • 401 Unauthorized:请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
  • 403 Forbidden:服务器收到请求,但是拒绝提供服务
  • 500 Internal Server Error:服务器发生不可预期的错误
  • 503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常

header

在请求报文和响应报文中都可以携带一些信息,通过与其他部分配合,能够实现各种强大的功能。这些信息位于起始行之下与请求实体之间,以键值对的形式,称之为首部。每条首部以回车换行符结尾,最后一个首部额外多一个换行,与实体分隔开。

  • 通用报头,既可以出现在请求报头,也可以出现在响应报头中
    Date:表示消息产生的日期和时间
    Connection:允许发送指定连接的选项,例如指定连接是连续的,或者指定“close”选项,通知服务器,在响应完成后,关闭连接
    Cache-Control:用于指定缓存指令,缓存指令是单向的(响应中出现的缓存指令在请求中未必会出现),且是独立的(一个消息的缓存指令不会影响另一个消息处理的缓存机制)

  • 请求报头,用于服务器传递自身信息的响应,常见的响应报头:
    Location:用于重定向接受者到一个新的位置,常用在更换域名的时候
    Server:包含可服务器用来处理请求的系统信息,与User-Agent请求报头是相对应的

  • 实体报头,实体报头用来定于被传送资源的信息,既可以用于请求也可用于响应。请求和响应消息都可以传送一个实体,常见的实体报头为:
    Content-Type:发送给接收者的实体正文的媒体类型
    Content-Lenght:实体正文的长度
    Content-Language:描述资源所用的自然语言,没有设置则该选项则认为实体内容将提供给所有的语言阅读
    Content-Encoding:实体报头被用作媒体类型的修饰符,它的值指示了已经被应用到实体正文的附加内容的编码,因而要获得Content-Type报头域中所引用的媒体类型,必须采用相应的解码机制。
    Last-Modified:实体报头用于指示资源的最后修改日期和时间
    Expires:实体报头给出响应过期的日期和时间

实体

请求发送的资源,或是响应返回的资源。

Http缓存

当我们发起一个http请求后,服务器返回所请求的资源,这时我们可以将该资源的副本存储在本地,这样当再次对该url资源发起请求时,我们能快速的从本地存储设备中获取到该url资源,这就是所谓的缓存。缓存既可以节约不必要的网络带宽,又能迅速对http请求做出响应。

先摆出几个概念:
新鲜度检测
再验证
再验证命中

我们知道,有些url所对应的资源并不是一成不变的,服务器中该url的资源可能在一定时间之后会被修改。这时本地缓存中的资源将与服务器一侧的资源有差异。

既然在一定时间之后可能资源会改变,那么在某个时间之前我们可以认为这个资源没有改变,从而放心大胆的使用缓存资源,当请求时间超过来该时间,我们认为这个缓存资源可能不再与服务器端一致了。所以当我们发起一个请求时,我们需要先对缓存的资源进行判断,看看究竟我们是否可以直接使用该缓存资源,这个就叫做新鲜度检测。即每个资源就像一个食品一样,拥有一个过期时间,我们吃之前需要先看看有没有过期。

如果发现该缓存资源已经超过了一定的时间,我们再次发起请求时不会直接将缓存资源返回,而是先去服务器查看该资源是否已经改变,这个就叫做再验证。如果服务器发现对应的url资源并没有发生变化,则会返回304 Not Modified,并且不再返回对应的实体。这称之为再验证命中。相反如果再验证未命中,则返回200 OK,并将改变后的url资源返回,此时缓存可以更新以待之后请求。

我们看看具体的实现方式:

新鲜度检测
我们需要通过检测资源是否超过一定的时间,来判断缓存资源是否新鲜可用。那么这个一定的时间怎么决定呢?其实是由服务器通过在响应报文中增加Cache-Control:max-age,或是Expire这两个首部来实现的。值得注意的是Cache-Control是http1.1的协议规范,通常是接相对的时间,即多少秒以后,需要结合last-modified这个首部计算出绝对时间。而Expire是http1.0的规范,后面接一个绝对时间。
再验证
如果通过新鲜度检测发现需要请求服务器进行再验证,那么我们至少需要告诉服务器,我们已经缓存了一个什么样的资源了,然后服务器来判断这个缓存资源到底是不是与当前的资源一致。逻辑是这样没错。那怎么告诉服务器我当前已经有一个备用的缓存资源了呢?我们可以采用一种称之为条件请求的方式实现再验证。
Http定义了5个首部用于条件请求:
If-Modified-Since
If-None-Match
If-Unmodified-Since
If-Range
If-Match

If-Modified-Since 可以结合Last-Modified这个服务器返回的响应首部使用,当我们发起条件请求时,将Last-Modified首部的值作为If-Modified-Since首部的值传递到服务器,意思是查询服务器的资源自从我们上一次缓存之后是否有修改。

If-None-Match 需要结合另一个Etag的服务器返回的响应首部使用。Etag首部实际上可以认为是服务器对文档资源定义的一个版本号。有时候一个文档被修改了,可能所做的修改极为微小,并不需要所有的缓存都重新下载数据。或者说某一个文档的修改周期极为频繁,以至于以秒为时间粒度的判断已经无法满足需求。这个时候可能就需要Etag这个首部来表明这个文档的版号了。发起条件请求时可将缓存时保存下来的Etag的值作为If-None-Match首部的值发送至服务器,如果服务器的资源的Etag与当前条件请求的Etag一致,表明这次再验证命中。

OAuth

OAuth是一个用于授权第三方获取相应资源的协议。与以往的授权方式不同的是,OAuth的授权能避免用户暴露自己的用户密码给第三方,从而更加的安全。OAuth协议通过设置一个授权层,以区分用户和第三方应用。用户本身可以通过用户密码登陆服务提供商,获取到账户所有的资源。而第三方应用只能通过向用户请求授权,获取到一个Access Token,用以登陆授权层,从而在指定时间内获取到用户授权访问的部分资源。

OAuth定义的几个角色:

Role Description
Resource Owner 可以授权访问某些受保护资源的实体,通常就是指用户
Client 可以通过用户的授权访问受保护资源的应用,也就是第三方应用
Authorization server 在认证用户之后给第三方下发Access Token的服务器
Resource Server 拥有受保护资源的服务器,可以通过Access Token响应资源请求
 +--------+                               +---------------+
 |        |--(A)- Authorization Request ->|   Resource    |
 |        |                               |     Owner     |
 |        |<-(B)-- Authorization Grant ---|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(C)-- Authorization Grant -->| Authorization |
 | Client |                               |     Server    |
 |        |<-(D)----- Access Token -------|               |
 |        |                               +---------------+
 |        |
 |        |                               +---------------+
 |        |--(E)----- Access Token ------>|    Resource   |
 |        |                               |     Server    |
 |        |<-(F)--- Protected Resource ---|               |
 +--------+                               +---------------+

从上图可以看出,一个OAuth授权的流程主要可以分为6步:

  1. 客户端向用户申请授权。
  2. 用户同意授权。
  3. 客户端通过获取的授权,向认证服务器申请Access Token。
  4. 认证服务器通过授权认证后,下发Access Token。
  5. 客户端通过获取的到Access Token向资源服务器发起请求。
    6.资源服务器核对Access Token后下发请求资源。

Https

简单的说 Http + 加密 + 认证 + 完整性保护 = Https

传统的Http协议是一种应用层的传输协议,Http直接与TCP协议通信。其本身存在一些缺点:

  1. Http协议使用明文传输,容易遭到窃听。
  2. Http对于通信双方都没有进行身份验证,通信的双方无法确认对方是否是伪装的客户端或者服务端。
  3. Http对于传输内容的完整性没有确认的办法,往往容易在传输过程中被劫持篡改。

因此,在一些需要保证安全性的场景下,比如涉及到银行账户的请求时,Http无法抵御这些攻击。
Https则可以通过增加的SSL\TLS,支持对于通信内容的加密,以及对通信双方的身份进行验证。

你可能感兴趣的:(Android 网络编程(http协议))