前言
本文并不是对HTTP协议科普的文章,不会对HTTP协议的基础进行详细的阐述,但是会从几个大的层面来分析HTTP协议是怎么工作的,让大家加深对网络请求原理的理解,本文将分别对不同类型的请求的请求报文,响应报文进行分析
概念
HTTP协议到底是个什么东西,其实就是官方指定了一些格式,大家在通信的时候都按照这个协议个格式组装报文,
然后自己解析报文进行操作,实际开发中,大量的第三方框架会把解析报文的工作进行封装
这里的通信又是建立在tcp协议的基础上,使用socket进行通信,
tcp协议会封装出一个报文,包括请求头,请求data,然后这个请求data里面有包括http协议的完整报文
HTTP 请求类型
HTTP 协议一共定义了八种请求类型,也就是我们经常用到的method类型
- GET 请求获取Request-URI所标识的资源
- POST 在Request-URI所标识的资源后附加新的数据
- HEAD 请求获取由Request-URI所标识的资源的响应消息报头
- PUT 请求服务器存储一个资源,并用Request-URI作为其标识
- DELETE 请求服务器删除Request-URI所标识的资源
- TRACE 请求服务器回送收到的请求信息,主要用于测试或诊断
- CONNECT 保留将来使用
- OPTIONS 请求查询服务器的性能,或者查询与资源相关的选项和需求
这八种类型,是在HTTP协议层面的定义,HTTP说,我定义了这么多请求类型,够大家使用的了,大家请求的时候不要再出现其他的类型了。
然后服务端收到完整报文的时候,解析请求类型,根据不同的类型去做不同的操作,比如接收到DELETE 类型的请求,就会删除指定的资源。
其实我们也完全可以只使用其中一种类型,然后通关传入的参数来决定是什么操作,比如同样是删除操作,我们使用GET 类型,并且传入两个参数,代表删除操作,以及删除的资源地址,同样能够达到DELETE的效果,但是这里面我们相当于自己又定义了一套”协议”
在我们实际的项目使用过程中,使用的最多的就是 GET POST 两种类型,在这两种类型里面,会衍生出多种不同的”操作”,比如 普通的接口请求,上传文件,下载文件等
HTTP 请求报文 响应报文
一个HTTP请求报文由请求行(request line)、请求头部(header)、空行和请求数据4个部分组成,下图给出了请求报文的一般格式。
一个HTTP 响应报文与请求报文的格式类似 由状态行、响应头部、空行 和 响应数据4个部分组成,下图给出了响应报文的一般格式。
普通接口请求
在日常开发中,使用场景最广泛的操作就是普通接口请求了,而普通接口请求,又可以分为GET,POST两种请求类型
GET请求接口
将参数直接拼接在了[请求行]中的URL 后面 body(请求数据)中无内容,请求头中不需要Content-Type Content-Length
请求报文
1 | GET /v1/test.html?param=1 HTTP/1.1 |
POST请求接口
将参数放到body(请求包体)里面,同时必须在请求头中增加Content-Type Content-Length
contentType:application/x-www-form-urlencoded
contentLength: body数据的长度
application/x-www-form-urlencoded:提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。大部分服务端语言都对这种方式有很好的支持
请求报文
1 | POST /v1/test.html HTTP/1.1 |
响应报文
无论上面的GET 请求还是POST 请求,其响应报文的格式都是一样的
1 | HTTP/1.1 200 OK |
响应行中的200 是状态码,包括我们常见的404 502等等
文件上传
文件上传一般用POST请求,将文件数据放到body中,但是根据请求头中Content-Type的不同,上传文件又可以分为两种形式
- Content-Type 直接指定文件类型,如image/jpeg, body中的数据为完整的图片数据
- Content-Type:multipart/form-data
Content-Type 直接指定文件类型
这种方式比较简单,只需要指定Content-Type Content-Length 即可
Content-Type是上传文件的mine类型,Content-Length是上传文件数据的大小,将上传的数据放到请求报文的body中即可
1 | POST /v1/upload/updateImgFile.html HTTP/1.1 |
multipart/form-data方式
上面第一种方式上传文件比较简单,但是灵活性不高,比如我们想在上传的时候携带一些参数,让服务端执行一些逻辑就没有办法做到
那multipart/form-data 其实就是表单上传的方式,表单的每一个field 可以是不同的数据类型
1 | POST /v1/upload/updateImgFile.html HTTP/1.1 |
上面是一个完整的POST请求,通过multipart/form-data的方式上传文件,并且携带了param1参数
Content-Type 不仅要设置为multipart/form-data 后面还必须增加一个boundary,这是一个随机生成的字符串,后面用来分隔不同的field
field之间用--boundary
分隔 最后以--boundary--
结束
最后上传图片的field Content-Disposition 里面增加了filename参数,用来告诉服务端,文件要以什么名字保存,当然,也可以不需要这个参数,由服务端来命名文件
注意请求的Content-Length
下载
下载一般使用GET请求,只需要指定资源的位置即可,服务端响应报文会把文件内容放到响应body里面,当然如果文件很大,报文可能会被分割成多帧发送,所以我门下载文件的时候,不是一次拿到所有数据,而是不断的进入回调,接收数据
全文件下载
请求报文
1 | GET /20160524GO0Z7WYI.png HTTP/1.1 |
响应报文
1 | HTTP/1.1 200 OK |
部分下载(断点续传)
只需要在普通下载的请求头中增加一个字段Range,来表示请求资源的数据偏移量,大小即可实现数据的指定部分下载。
Range: bytes=2000- 下载从2000字节开始,前面的不需要
Range: bytes=2000-3000 下载从2000字节到3000字节的内容,其他范围的内容不需要
Range: bytes=-3000 下载最后3000字节的内容,其他范围的内容不需要
Range: bytes=2000-3000,5000-8000 下载从2000字节到3000字节,5000到8000范围的内容,其他范围的内容不需要
既然能够指定下载一个文件的某一部分数据,那么断点续传就不难实现了,当我们下载文件的时候,首先查看本地是否已经有这个文件的临时数据,如果有的话,那么我们在下载的时候,就不用从0开始下载,而是指定下载的范围从当前本地数据的长度,一直到文件最后,当接收到数据之后直接append到本地文件后面即可
1 | GET /20160524GO0Z7WYI.png HTTP/1.1 |
响应报文1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18HTTP/1.1 206 OK //注意如果请求使用了Range,这里返回206
Server: AliyunOSS
Date: Tue, 24 May 2016 09:11:25 GMT
Content-Type: image/jpeg
Content-Length: 12418
Connection: keep-alive
x-oss-request-id: 57441ABC49C125CB26DB0BF9
x-oss-bucket-storage-type: standard
Accept-Ranges: bytes
Content-Range: bytes 0-100/2350 //2350:文件总大小
ETag: "F30283D509A7787153F98BEC6D5474E3"
Last-Modified: Tue, 24 May 2016 09:05:33 GMT
x-oss-object-type: Normal
Content-Disposition: inline;filename=20160524GO0Z7WYI.png
Cache-Control: no-cache
x-oss-server-time: 15
*******图片数据***********
多线程下载工具
假设一个文件400byte 那么,我们可以将文件分为4个部分,0-100,101-200,201-300,301-400,同时开4个线程去同时下载,并建立4个临时文件保存起来,当四个下载任务都完成后,将文件按照顺序合并即可