美文网首页
Android 你不得不学的HTTP相关知识

Android 你不得不学的HTTP相关知识

作者: Amter | 来源:发表于2020-07-23 00:40 被阅读0次

    本章目录

    • 1、http是怎么定义的?
    • 2、http是怎么工作的?
    • 3、报文是什么?
    • 4、URL是什么?
    • 5、RequestMethod请求方法有哪些?
    • 6、State Code状态码
    • 7、Header头部
    • 8、Cache缓存
    • 9、http的发展史
    • 10、断点续传功能是怎么实现的

    本章结构图

    image

    1、http是怎么定义的?

    1.1、超文本传输协议;

    超文本传输协议(英语:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。

    设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。通过HTTP或者HTTPS协议请求的资源由统一资源标识符(Uniform Resource Identifiers,URI)来标识。

    1.2、http在网络中的分层;

    最开始的网络分层是分了有七层,如下;

    OSI模型:

    image

    后来由于最上面三层(应用层、表示层和会话层)在TCP/IP组中是一个应用层,就合并到应用层了;

    TCP/IP组模型:

    image

    而HTTP在网络分层中是属于应用层的协议;

    2、http是怎么工作的?

    http的工作方式通常是由客户端和服务端协同完成的;

    通常,由客户端发起一个请求,创建一个到服务器指定端口(默认是80)的TCP链接,服务器则在这个端口监听客户端的请求,当接收到请求后,会根据客户端的请求,返回对应的内容,比如html文本,图片之类的,并且返回对应的状态码来告诉客户端请求的状态是否成功;

    3、报文是什么?

    3.1、http的报文是什么?

    HTTP报文是在HTTP应用程序之间发送的数据块。

    将http比喻成快递,那么http报文就是包裹的快递单,包含来姓名,地址,邮政编码,表示我这个快递要寄到哪里去,而快递中心收到这个快递后,就会通过这个快递单,来判断这个包裹要寄送到哪里去,而这个信息就是通过快递单来获取的;

    那么同样http报文也是类似的道理,客户端发送一个请求,带上报文,服务端接收到请求后,解析这个报文,就知道客户端需要获取什么东西来;

    而服务端想客户端返回内容时,也会带上报文,表示我返回的内容是什么,方便客户端通过报文来解析数据,并处理的流程;

    3.2、http报文的格式

    http报文分为请求报文和相应报文;

    • 请求报文:客户端向服务器发送的报文;
    • 相应报文:服务端向客户端发送的报文;

    请求报文的格式:

    由请求行,请求头,空行,请求数据这四部分组成

    image

    举例:请求百度的地址,打开浏览器的调试功能,查看请求报文;

    image

    响应报文的格式:

    由状态行,请求头,空行,请求数据这四部分组成

    image

    举例:同样通过浏览器查看百度页面的响应报文;

    image

    4、URL是什么?

    4.1、URL是怎么定义的?

    URL,全称:Uniform Resource Locator 译名:统一资源定位符,用于准确描述Internet上某一资源的地址;

    我们访问的网页都是有地址的,而地址通常指向某个服务器上的资源;

    4.2、URL的格式是怎样的?

    URL的格式是由协议类型(http,https等),服务器地址(host),端口号(port),路径(path)这几部分组成的;

    比如百度的地址:https://www.baidu.com/

    格式如下:http://host[:port][/path]

    • 协议类型:表示使用哪种网络协议来进行网络请求,比如HTTP,HTTPS;
    • 服务器地址:表示主机,或者域名,或者IP地址;
    • 端口号:如果没有指定的话,默认为80;
    • 路径:表示指定请求资源的URL,默认会带上“/”,一般都是浏览器给我们加上的;

    5、RequestMethod请求方法有哪些?

    5.1、请求方法

    HTTP请求的方法有很多,如下:

    • GET:使用GET的请求用于从服务器获取数据;

    • HEAD:和GET请求相似,但是没有响应体;

    • POST方法:用于将内容提交到服务器,通常用于修改或者删除服务器上的资源;

    • PUT方法:通常用于修改服务器上的数据;

    • DELETE方法:删除服务器指定的资源;

    • CONNECT方法:建立一个到由目标资源标识的服务器的隧道,用于代理服务器;

    • OPTIONS方法:用于描述目标资源的通信选项,通常用于跨域请求;

    • TRACE方法:沿着到目标资源的路径执行一个消息环回测试,用于追踪请求;

    5.2、GET和POST请求的区别

    我们最常用的的请求方法,基本上就是GET和POST请求了,那么我们来看一下他们的区别吧;

    通常在浏览器上输入一个地址进行请求,一般都是通过GET请求方式,而POST请求一般用于提交内容,将需要提交给服务器的参数放到body里面,进行请求;

    来看看w3school列举的差异点:

    image

    疑问:
    1,安全性:

    GET的请求在浏览器上是可以看到请求的参数的,基本上来说没有安全性可言;

    而POST请求在浏览器上看不到请求参数,是不是表示就是安全的呢?

    并不是,别人可以通过抓包的方式来获取到你的请求参数,所以并不是安全的,要想安全的传输只能通过有加密方式的HTTPS请求;

    2,POST方法是否会产生两个TCP数据包?

    答案是:不一定;

    这个不是必然会产生两个TCP数据包,而是看浏览器是否做了发送两次TCP数据包的处理,如果有做处理的话就会发送两次TCP数据包;

    网上已经有文章验证过了,我这里就不再多说了,经验证的结果为:Chrome和Safari浏览器会发送两次TCP数据包,而Firefox浏览器只发送了一次;

    详情请参考:听说『99% 的人都理解错了 HTTP 中 GET 与 POST 的区别』??

    3,URL过长会导致什么问题?

    我们先用postman来模拟一下看看,弄一个超长的URL,请求一下看会不会报错;

    image

    从图片上可以看出,postman直接返回了414 Request-URL Too Long,表示当前URL过长了;

    用浏览器请求返回的错误信息也是一样:

    image

    那么这里是否会有疑问,为什么URL过长会报错? 是服务器处理不了,还是postman处理不了? 还是http协议规定的URL不能超过多长呢?

    查看RFC的http的相关文档(RFC 2616 - HTTP/1.1)发现里面的一段话,如下:

    The HTTP protocol does not place any a priori limit on the length of
    a URI. Servers MUST be able to handle the URI of any resource they
    serve, and SHOULD be able to handle URIs of unbounded length if they
    provide GET-based forms that could generate such URIs. A server
    SHOULD return 414 (Request-URI Too Long) status if a URI is longer
    than the server can handle (see section 10.4.15).

    翻译过来的意思就是:

    HTTP协议没有对长度进行任何限制,服务器必须能够处理其任何资源的URI服务,并且应该能够处理长度不受限制的URI,如果URI较长,则应返回414(请求URI太长)状态超出服务器的处理能力;

    看到这里,我们就明白了,http协议并没有限制URL的长度,对URL长度做处理的,只有服务器或者浏览器,所以URL过长导致的报错是由服务器或者浏览器处理的;

    4,GET方法可以带Body吗?

    答案是:可以的!

    为什么GET方法可以带Body吗?不是说GET方法是通过URL来取资源的吗?

    来看一下RFC的协议中,对于GET方法的定义:

    The GET method means retrieve whatever information (in the form of an
    entity) is identified by the Request-URI.

    翻译过来的意思就是GET方法是通过URL来检索服务器上的信息,并没有说不能带上Body;

    那么到这里你是否就有疑惑了? 他没说不就代表他可以带上Body来请求啊;别急,我们继续分析;

    再来看另外一份RFC协议对于GET请求带Body的解释:

    A payload within a GET request message has no defined semantics;
    sending a payload body on a GET request might cause some existing
    implementations to reject the request.

    翻译过来的意思就是带上Body的GET方法,可能会导致拒绝请求,有可能是服务器拒绝了,也有可能是浏览器或者框架拒绝请求;

    结论:GET方法是可以带上Body请求的,但是可能会发生拒绝请求的错误,或者一些其他的错误出现;

    那么对于GET方法带上Body的测试这里就不多说了,感兴趣的请参考:谁说 HTTP GET 就不能通过 Body 来发送数据呢?

    6、State Code状态码

    6.1、状态码是什么?

    状态码是客户端向服务端请求后,服务端会返回一个数字来告诉端侧请求的状态,比如200,表示请求成功了,比如404,客户端错误了;这样客户端再拿到状态码之后再做相应的处理,比如是否重试,比如展示错误页面,比如提示用户操作不当之类的;

    6.1、状态码有哪些?

    看一下菜鸟教程对于状态码的定义:

    image

    如图所示,http状态码主要分为5种类型,分别为1xx,2xx,3xx,4xx,5xx等开头的状态码;

    每一个状态码以x开头的都可归类为某一种类型的状态;比如200(请求成功),404(客户端错误)等;

    状态码的种类有很多,这里就不一一介绍了;

    7、Header头部

    7.1、Header是用来干嘛的?

    Header其实是一个键值对,是属于元数据,用于告诉服务器,我要取什么样的数据或者我要做什么样的操作;

    比如:Accept: text/plain,表示客户端能接受文本数据的返回;

    除了先有的一些标准的请求头,我们还可以自定义请求头,比如:user:"张三",表示我要传 "张三"的Header到服务器,服务器再做相应的处理;

    7.2、Header有哪些?

    HTTP头字段按照实际用途可以分为四种类型,分别为通用头,请求头,响应头和实体头这四种;

    • 通用头:是客户端和服务器都可以使用的头部,可以在客户端、服务器和其他应用程序之间提供一些非常有用的通用功能,如Date头部;
    • 请求头:是请求报文特有的,它们为服务器提供了一些额外信息,比如客户端希望接收什么类型的数据,如Accept头部;
    • 响应头:便于客户端提供信息,比如,客服端在与哪种类型的服务器进行交互,如Server头部;
    • 实体头:指的是用于应对实体主体部分的头部,比如,可以用实体头部来说明实体主体部分的数据类型,如Content-Type头部;

    7.3、常见的Header的类型有哪些?

    1,Host

    客户端指定自己想访问的WEB服务器的域名/IP 地址和端口号;

    2,Content-Type

    用于指定请求体的类型,主要有四种;

    (1)text/html:用于告诉服务器需要响应的类型为文本数据类型;

    (2)x-www-form-urlencoded:表单类型,用于web页面纯文本表单提交数据到服务器,比如注册页面数据的提交;

    (3)multitype/form-data:用于web页面带二进制文件的表单提交方式,比如修改用户头像,会上传图片到服务器;

    (4)application/json , image/jpeg , application/zip ...:提交单项内容到服务器,比如提交json,提交image,提交zip包到服务器;

    3,Content-Length

    用于指定响应体的长度,表示我这次请求需要返回多少字节的内容,多用于分块传输;

    4,User-Agent

    用于向服务端表明身份信息,表示我是来自手机客户端的请求,还是来自某个浏览器的请求;

    5,Range

    表示想从服务器取哪部分的内容,比如byte:start-end;用于多线程下载或者断点续传;

    6,Accept

    告诉服务器客户端能接受什么类型的数据,比如text/html;

    7,Accept-Charset

    告诉服务器客户端能接受的的字符集,比如utf-8;

    8,Accept-Encoding

    告诉服务器客户端能接受的压缩编码类型,如zip;

    9,Content-Encoding

    服务器告诉客户端自己使用了什么压缩方法,如gzip,deflate等;

    HTTP的Header类型是在是太多了,这里就不一一介绍了,感兴趣的请参考:
    「Android系列之网络(二)----HTTP请求头与响应头

    8、Cache缓存

    8.1、http为什么需要缓存?

    1,通过网络获取内容,会受速度影响并且开销很大,需要在客户端和服务器之间建立通讯,然后通过传包的方式来进行通讯,受网络速度影响,有可能会响应比较慢,导致前端的展示体验不好;

    2,减少开销,如果每一次请求都从服务器取的话,那么服务器将会面临巨大的压力,有可能会挂掉,导致访问不了;

    3,使用缓存还可以减少网络带宽的占用,过多的请求会导致网络阻塞,从而响应速度也变慢;

    4,减少无意义的重复请求,比如某个页面的数据,运营一天才会去修改一次,但是我每次进来这个页面都去从服务器请求数据,这样是没有意义的,只会导致资源的浪费;

    所以使用缓存可以大大的提升响应速度,降低服务器压力,减少带宽的占用,因此HTTP的缓存是至关重要的;

    8.2、http的缓存机制是什么?

    1,通过 ETag 验证缓存的响应

    (1)ETag是什么?

    ETag 本质上是一个header,也被称为验证令牌,是由服务器根据根据文件生成的hash值或者其他的某个值;

    (2)验证令牌的诞生旨在解决什么问题?

    假如我们本地的数据是有缓存时效的,当我们从本地取数据的时候,发现缓存时效过期了,这时候就会去服务器那边取数据,但是此时从服务器取回来的数据和本地的数据是一样的,没有什么变化,只是本地的缓存时效过期了,这时候从服务器取回来的数据就没有意义了,还浪费了请求所消耗的资源;

    那么验证令牌就是为了解决这类问题而诞生的;

    (3)验证令牌是怎么解决这类问题的?

    前面说了,验证令牌本质上是一个header,我们去服务器取数据的时候会带上这个header,比如 ETag:"xxxxxx"; 服务器收到这个header之后,就会去做验证,如果验证对比了令牌后发现,没有变化,则返回“304 Not Modified”响应,告诉浏览器缓存重点数据没有发生什么变化,可以继续使用,那么我们接受到响应后,更新本地的缓存时效,进而继续使用缓存;

    借用官方的图:


    image.png

    2,Cache-Control 缓存控制

    (1)Cache-Control是用来干嘛的?

    Cache-Control是用来定义缓存策略的,比如定义某个资源在什么场景下,缓存多长的时间,本质上是一个header;

    Cache-Control是在 HTTP/1.1 规范中定义的;

    (2)Cache-Control怎么定义缓存策略?

    Cache-Control通过header定义的缓存指令来实现缓存策略,比如Cache-Control:max-age = 180;

    (3)缓存指令有哪些?

    请求指令

    • no-cache:会先通过ETag验证令牌和服务器进行通讯,判断服务器的数据是否有修改过,如果有修改过,则使用服务器返回的新的数据,否则的话就取缓存,使用这个指令会和服务器进行一次通讯;

    • no-store:指令为"no-store"的情况下,一律不进行缓存,都是从服务器取数据,一般用于需要安全的场景或者需要实时刷新的场景;

    • max-age:表示当前请求的响应体的有效时间为多长,超过了这个时效则从服务器取数据;

    • public:表示可以被任何中间者(代理服务器,cdn等)或者浏览器缓存数据,通常情况下,public并不是必须的指令,有其他指令(比如max-age)表示了该请求可以被缓存;

    • private:表示不可以被任何中间者(代理服务器,cdn等)缓存数据,但是浏览器可以缓存该指令的数据;

    3、Expires缓存头

    Expires相应头包含日期和时间,下次请求时,会将本地时间和这个时间做比较,如果如果缓存有效,则取缓存,但是由于本地时间和服务器时间不同步,用这个来判断缓存时效会存在不准的问题,因此在HTTP1.1之后更多的是使用Cache-Control 指令,更加灵活;

    4、Cache-Control在okhttp中的体现

      final CacheControl.Builder builder = new CacheControl.Builder();
                builder.noCache();//不使用缓存,全部走网络
                builder.noStore();//不使用缓存,也不存储缓存
                builder.maxAge(10, TimeUnit.MILLISECONDS);//指示客户机可以接收生存期不大于指定时间的响应。
                CacheControl cache = builder.build();//cacheControl
    

    9、http的发展史

    9.1、HTTP 0.9

    万维网协会(World Wide Web Consortium,W3C)和互联网工程任务组(IETF)在1991年的时候制定了 HTTP 0.9 标准,那时候只支持GET方法请求;

    9.2、HTTP 1.0

    从单一的GET方法请求,新增了POST请求,支持发送任何格式的内容,包括文本,视频,音乐,和二进制文件;

    请求体和返回体的格式也变了,新增了头信息(Header),状态码(status code),多字符集支持、多部分发送(multi-part type)、权限(authorization)、缓存(cache)、内容编码(content encoding)等功能;

    缺点

    (1)连接无法复用,浏览器和服务器只能建立短暂的TCP连接,当请求完毕之后,就关闭该TCP连接;如果需要重新请求,则需要重新建立TCP连接,会导致资源的浪费,以及响应的时间;

    (2)Head-Of-Line Blocking(HOLB,队头阻塞),在TCP连接中,请求是有序的,只有当服务器处理完前一个请求后,才会处理下一个请求,如果前一个请求速度较慢,就会造成后续请求阻塞等待的情况出现;

    9.3、HTTP 1.1

    HTTP 1.1是当前最流行的http版本;

    优化点
    (1)缓存:在 HTTP 1.0 中主要使用 header 里的 If-Modified-Since,Expires 来做为缓存判断的标准,HTTP 1.1则引入了更多的缓存控制策略例如 Entity tag,If-Unmodified-Since等更多可供选择的缓存头来控制缓存策略。

    (2)带宽的优化:新增了range头字段,用于分块传输,允许请求当前文件的部分内容,这样可以大大减少网络带宽的占用;

    (3)新增了24 个错误状态响应码

    (4)长链接:头字段新增了Connection:keep-alive,表示可以复用一部分链接,在tcp连接上可以传达多个请求,以此来减少建立和连接带来的消耗;

    (5)增加管线化技术(pipelining),在当前请求还没有返回时,可以发送下一个请求到服务器,以此来降低请求时间;

    缺点

    (1)长链接:虽然加入长链接可以减少建立和连接带来的消耗,但是不同的域名的链接不能复用,只能重新创建长链接,会耗费资源,并且给服务器带来巨大的压力;

    (2)在header中携带请求的数据量过大,造成流量的浪费,如果每次请求header的内容不变,但是header携带的数据量又很大的情况下,就会造成资源的浪费;

    (3)HTTP 1.1虽然引入了pipelining来解决队头阻塞问题(Head-Of-Line Blocking),即浏览器可以同时发送多个请求给服务器,不必等到上一个请求返回之后再进行请求,但是服务器的处理是等处理完当前请求的响应之后,才会去处理下一个请求的响应,即使当前很多请求都已经处理完了,服务器还是得根据请求的顺序来进行响应;

    因此它不是真正的多请求协议,但是是一个很好的改进;

    9.4、HTTP 2.0

    HTTP2.0基于谷歌开发的SPDY协议,而HTTP 2.0相对于HTTP 1.1带来了什么新的改进呢?

    优化点:

    (1)多路复用:对于HTTP1.1中,如果当前有多个请求,请求的发送都是串行执行的,对于宽带的利用效率不高,但是在HTTP 2.0中,多个请求可以并行请求,大大的提升了宽带的利用率;

    (2)Header压缩:使用首部表来跟踪和存储之前发送的键值对,对于相同的内容,不会再每次请求和响应时发送。

    (3)数据优先级:由于请求可以并发发送给服务器,但是服务器还是遵循先进先出的规则来处理请求,但是在HTTP 2.0中可以设置当前请求的优先级,这样服务器在处理请求的响应时,会优先返回优先级较高的请求;

    (4)服务端推送:对于请求,一般都是浏览器或者客户端发送给服务器,服务器处理之后再返回,但是在HTTP 2.0中服务器可以推送相关文件给客户端,客户端再进行相应的处理,而不必等客户端发送请求之后再返回给客户端;

    10、断点续传功能是怎么实现的?

    10.1、原理

    原理很简单,就是从停止下载的地方继续下载,比如我下载了10兆,文件总共有20兆,此时的断点下载就是从10兆开始进行续传,继续下载的;

    10.2、核心

    通过http的Range头字段来实现的,Range头字段支持从服务器或者指定内容范围大小的文件,比如我想要或者某个文件的前1024字节的数据,那么我只需要传
    Range: bytes=0-1024 (0到1024字节的数据),这样就可以从服务器获取到对于字节的数据了;

    10.3、好处

    断点续传的好处就是传输效率高,比如下载一个文件,在传输过程中受网络影响中断了,这时不需要在开头重新下载,而是在停止的地方继续下载;

    断点续传还可以通过多线程来提高效率,比如下载一个文件,我可以开10个线程或者20个线程来分段下载文件,这样可以大大的提高下载速度,像迅雷或者百度云大多都是这种原理,只是更加复杂;至于最多能开多少线程进行下载, 要看当前客户端的性能;

    10.3、客户端的实现

    数据库:用于存储断点下载的其实位置;

    多线程:用于加快下载速度;

    RandomAccessFile类:Java提供的对文件内容的访问,既可以读文件也可以写文件,可以访问文件的任意位置适用于由大小已知的记录组成的文件;

    下面从一张图来看看具体实现:

    image.png

    参考&感谢

    关于我

    兄dei,如果我的文章对你有帮助的话,请给我点个❤️,也可以关注一下我的Github博客;

    相关文章

      网友评论

          本文标题:Android 你不得不学的HTTP相关知识

          本文链接:https://www.haomeiwen.com/subject/mfckphtx.html