Android HTTP

该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽可能按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索》以及《深刻理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相关知识,另外也借鉴了其余的优质博客,在此向各位大神表示感谢,膜拜!!!html


前言

本篇文章是来讲说HTTP那些事。面试

HTTP简介

Web 使用一种名为 HTTP ( HyperText Transfer Protocol ,超文本传输协议的协议做为规范,完成从客户端到服务器端等一系列运做流程。本文探讨的是HTTP/1.1版本。这仍然是大多数网站采用的HTTP协议
咱们先看一下下面这张广为流传的图。
网路传输的4层结构算法

那些与HTTP协议密切相关的协议

IP

IP 协议的做用是把各类数据包传送给对方。而要保证确实传送到对方那里,则须要知足各种条件。其中两个重要的条件是 IP 地址和 MAC地址( Media Access Control Address )。IP 地址指明了节点被分配到的地址, MAC 地址是指网卡所属的固定地址。 IP 地址能够和 MAC 地址进行配对。 IP 地址可变换,但 MAC地址基本上不会更改。IP使用 ARP 协议凭借 MAC 地址进行通讯浏览器

TCP(确保可靠性的协议)

按层次分, TCP 位于传输层,提供可靠的字节流服务。所谓的字节流服务( Byte Stream Service )是指,为了方便传输,将大块数据分割成以报文段( segment )为单位的数据包进行管理。而可靠的传输服务是指,可以把数据准确可靠地传给对方。缓存

TCP链接的3次握手

为了准确无误地将数据送达目标处, TCP 协议采用了三次握手( three-way handshaking )策略。
握手过程当中使用了 TCP 的标志( flag ) —— SYN ( synchronize ) 和ACK ( acknowledgement )。发送端首先发送个带 SYN 标志的数据包给对方。接收端收到后,回传一个带有 SYN/ACK 标志的数据包以示传达确认信息。最后,发送端再回传一个带 ACK 标志的数据包,表明 “ 握手 ” 结束。若在握手过程当中某个阶段莫名中断, TCP 协议会再次以相同的顺序发送相同的数据包。服务器

整个过程以下图所示
3次握手网络

为何须要3次握手

为何须要3次握手,若是面试中问到了TCP相关知识,那么这个问题也几乎是必问的,为何是3次,而不是1次,2次或者4次,5次??多线程

首先咱们知道无论是客户端或者服务端发送数据都会消耗网络流量,还会形成许多没必要要的通讯开销,浪费资源,因此咱们在保证TCP可靠性的前提下所经历的通讯次数天然越少越好。app

TCP的可靠性含义咱们上面已经说了,那咱们就从3次握手分析,若是只有1次握手,客户端只向服务端发送数据,那么就谈不上可靠性了,由于服务端都没有回复,那么咱们来看只有2次握手行不行,若是只有2次握手,客户端只向服务端发送数据,服务器也向客户端回复我收到数据了,可是考虑此时若是发送数据的过程当中数据丢失了,服务端认为链接创建了(数据我已经发出去了),但是客户端没有收到数据,客户端认为链接没有创建,就会重复请求,而这对与服务端来讲就又是一个全新的链接。一言以蔽之:第三次握手是为了防止:若是客户端迟迟没有收到服务器返回确认报文,这时会放弃链接,从新启动一条链接请求,但问题是:服务器不知道客户端没有收到,因此他会收到两个链接,浪费链接开销。若是每次都是这样,就会浪费多个链接开销。大数据

HTTP详解

HTTP的报文结构

用于 HTTP 协议交互的信息被称为 HTTP 报文。请求端(客户端)的HTTP 报文叫作请求报文,响应端(服务器端)的叫作响应报文。HTTP 报文自己是由多行(用 CR+LF 做换行符)数据构成的字符串文本。HTTP 报文大体可分为报文首部和报文主体两块。二者由最初出现的空行( CR+LF )来划分。一般,并不必定要有报文主体。

HTTP的报文结构

HTTP的请求以及响应报文结构

HTTP的请求以及响应报文结构

HTTP的报文头部

下面的是请求某网站时,请求报文以及响应报文的首部信息。

请求报文首部

Host: hackr.jp
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:61.0) Gecko/20100101 Firefox/61.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1

响应报文首部

HTTP/1.1 200 OK
Date: Thu, 23 Aug 2018 08:17:43 GMT
Server: Apache
Last-Modified: Tue, 08 Jan 2013 08:53:29 GMT
ETag: "25e-4d2c3145df440-gzip"
Accept-Ranges: bytes
Vary: Accept-Encoding,User-Agent
Content-Encoding: gzip
Content-Length: 379
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Content-Type: text/html

由上可知HTTP 首部字段是由首部字段名和字段值构成的,中间用冒号 “:” 分隔。

HTTP的报文头部类型

HTTP 首部字段根据实际用途被分为如下 4 种类型。

通用首部字段( General Header Fields )请求报文和响应报文两方都会使用的首部。

首部字段名 说明
Cache-Control 控制缓存的行为
Connection 逐跳首部、链接的管理
Date 建立报文的日期时间
Pragma 报文指令
Trailer 报文末端的首部一览
Transfer-Encoding 指定报文主体的传输编码方式
Upgrade 升级为其余协议
Via 代理服务器的相关信息
Warning 错误通知

请求首部字段( Request Header Fields )从客户端向服务器端发送请求报文时使用的首部。补充了请求的附加内容、客户端信息、响应内容相关优先级等信息。

首部字段名 说明
Accept 用户代理可处理的媒体类型
Accept-Charset 优先的字符集
Accept-Encoding 优先的内容编码
Accept-Language 优先的语言(天然语言)
Authorization Web 认证信息
Expect 期待服务器的特定行为
From 用户的电子邮箱地址
Host 请求资源所在服务器
If-Match 比较实体标记( ETag )
If-Modified-Since 比较资源的更新时间
If-None-Match 比较实体标记(与 If-Match 相反)
If-Range 资源未更新时发送实体 Byte 的范围请求
If-Unmodified-Since 比较资源的更新时间(与 If-Modified-Since 相反)
Max-Forwards 最大传输逐跳数
Proxy-Authorization 代理服务器要求客户端的认证信息
Range 实体的字节范围请求
Referer 对请求中 URI 的原始获取方
TE 传输编码的优先级
User-Agent HTTP 客户端程序的信息

响应首部字段( Response Header Fields )从服务器端向客户端返回响应报文时使用的首部。补充了响应的附加内容,也会要求客户端附加额外的内容信息。

首部字段名 说明
Accept-Ranges 是否接受字节范围请求
Age 推算资源建立通过时间
ETag 资源的匹配信息
Location 令客户端重定向至指定 URI
Proxy-Authenticate 代理服务器对客户端的认证信息
Retry-After 对再次发起请求的时机要求
Server HTTP 服务器的安装信息
Vary 代理服务器缓存的管理信息
WWW-Authenticate 服务器对客户端的认证信息

实体首部字段( Entity Header Fields )针对请求报文和响应报文的实体部分使用的首部。补充了资源内容更新时间等与实体有关的信息。

首部字段名 说明
Allow 资源可支持的 HTTP 方法
Content-Encoding 实体主体适用的编码方式
Content-Language 实体主体的天然语言
Content-Length 实体主体的大小(单位:字节)
Content-Location 替代对应资源的 URI
Content-MD5 实体主体的报文摘要
Content-Range 实体主体的位置范围
Content-Type 实体主体的媒体类型
Expires 实体主体过时的日期时间
Last-Modified 资源的最后修改日期时间

HTTP 首部字段将定义成缓存代理和非缓存代理的行为,分红 2 种类型

  1. 端到端首部( End-to-end Header )
    分在此类别中的首部会转发给请求 / 响应对应的最终接收目标,且必须保存在由缓存生成的响应中,另外规定它必须被转发。
  2. 逐跳首部( Hop-by-hop Header )
    分在此类别中的首部只对单次转发有效,会因经过缓存或代理而再也不转发。 HTTP/1.1 和以后版本中,若是要使用 hop-by-hop 首部,需提供 Connection 首部字段。

下面列举了 HTTP/1.1 中的逐跳首部字段。除这 8 个首部字段以外,其余全部字段都属于端到端首部

  • Connection
  • Keep-Alive
  • Proxy-Authenticate
  • Proxy-Authorization
  • Trailer
  • TE
  • Transfer-Encoding
  • Upgrade

关于各个首部命令的详细参数可参见HTTP Headers

HTTP进阶

若是这篇文章到上面为止,那跟手册貌似没有什么区别,以前听到过一位大神说的话,掌握一门技术,不只须要知道这门技术能作到什么,也要知道它不能作到什么,在掌握一门技术的边界以后,便对一门技术游刃有余了,毕竟技术那么多,推陈换代那么快,对于大多数人来讲没有精力貌似也不是十分必要去记忆技术的每个细节(即便记忆了,有许多细节是咱们日常用不到的,也就渐渐遗忘了)。在咱们掌握边界之后,遇到问题时,咱们知道这个问题能依靠该项技术解决,至于怎么解决,那时咱们在去查相应手册便可。

那对于本篇的HTTP来讲,咱们就从如下两方面进行分析

HTTP能作到什么

咱们下面结合实际工做中的所遇到的HTTP的应用场景分为两大方面

访问大数据(图片,视频,大文件)时

在访问这些大数据时,咱们每每会遇到如下问题

1. **如何请求部分数据?**
2. **假设已请求了某资源的部分数据,程序终止了,服务器更新了该资源,客户端如何作,即已缓存的数据是否可信?**

咱们一般在作下载功能的时候每每须要断点续传甚至多线程断点续传,那么上面的问题就确定会遇到。下面咱们一一解答
1.使用Range来请求某个资源的部分数据

Range: bytes=bytes=200-1000, 2000-6576, 19000-
表示请求获取从第 200 字节至第1000 ,2000-6576,19000以后全部字节的资源。
在一个  Range 首部中,能够一次性请求多个部分,服务器会以 multipart 文件的形式将其返回。
若是服务器返回的是范围响应,须要使用 206 Partial Content 状态码。
假如所请求的范围不合法,那么服务器会返回  416 Range Not Satisfiable 状态码,表示客户端错误。

2.ETag以及If-Match If-None-Match If-Range

响应首部字段ETag 能告知客户端实体标识。它是一种可将资源以字符串形式作惟一性标识的方式。服务器会为每份资源分配对应的 ETag值。另外,当资源更新时, ETag 值也须要更新。生成 ETag 值时,并无统一的算法规则,而仅仅是由服务器来分配。

ETag 中有强 ETag 值和弱 ETag 值之分。
强 ETag 值,不论实体发生多么细微的变化都会改变其值。

ETag: "1234"

弱 ETag 值,只用于提示资源是否相同。只有资源发生了根本改变,产生差别时才会改变 ETag 值。这时,会在字段值最开始处附加 W/

ETag: W/"1234"

请求首部字段If-Match If-None-Match If-Range
形如 If-xxx 这种样式的请求首部字段,均可称为条件请求。服务器接收到附带条件的请求后,只有判断指定条件为真时,才会执行请求。
If-Match ,它会告知服务器匹配资源所用的实体标记( ETag )值。这时的服务器没法使用弱 ETag 值。服务器会比对 比If-Match 的字段值和资源的 ETag 值,仅当二者一致时,才会执行请求。反之,则返回状态码 412 Precondition Failed 的响应。还可使用星号( * )指定 If-Match 的字段值。针对这种状况,服务器将会忽略 ETag 的值,只要资源存在就处理请求。

If-None-Match 只有在 If-None-Match 的字段值与 ETag 值不一致时,可处理该请求。与 If-Match 首部字段的做用相反

If-Range 浏览器告诉 WEB 服务器,若是我请求的对象没有改变,就把我缺乏的部分给我,若是对象改变了,就把整个对象给我。浏览器经过发送请求对象的ETag 或者本身所知道的最后修改时间给 WEB 服务器,让其判断对象是否改变了。老是跟 Range 头部一块儿使用。

使用形式以下

If-Range: Wed, 21 Oct 2015 07:28:00 GMT
Range: bytes=bytes=200-1000
If-Range: "1234"
Range: bytes=bytes=200-1000

If-Range 头字段一般用于断点续传的下载过程当中,用来自从上次中断后,确保下载的资源没有发生改变。

一般状况下的HTTP请求与响应

咱们如今的服务器大可能是符合RESTFUL规范的,做为客户端(网页、Android、IOS)来讲,咱们与服务器的一般交互是数据量比较小的操做,增删改查,传递以及解析显示JSON数据。这是咱们一般使用HTTP的场景。这种场景下所经常使用的HTTP头部字段是包含上述访问大数据(图片,视频,大文件)时的请求字段的,这些首部字段各有含义,见HTTP Headers

HTTP不能作到什么(缺陷)

  • 一条链接上只可发送一个请求。
  • 请求只能从客户端开始。客户端不能够接收除响应之外的指令。
  • 请求 / 响应首部未经压缩就发送。首部信息越多延迟越大。
  • 发送冗长的首部。每次互相发送相同的首部形成的浪费较多。

备注:因为上述HTTP/1.1协议的缺陷,SPDYWebSocket 等协议纷纷出现,还有HTTP/2.0版本,这些协议的出如今必定程度上弥补了HTTP/1.1协议的缺陷。感兴趣的同窗能够深刻了解。


本篇总结

本篇文章介绍了HTTP协议。从TCP/IP到HTTP以及HTTP进阶,层层递进,但愿读者有些许收货。


此致,敬礼

相关文章
相关标签/搜索