0. HTTP直观印象,HTTP是什么?HTTP的工作方式。
- 直观印象:我们使用浏览器输入网址访问网页;客户端开发过程中调用接口,服务器给我们返回数据。
- HTTP是什么:HTTP,英文全称HyperText Transfer Protocol(超文本传输协议)
协议:双方都应该遵守的一种规范,俗称江湖规矩,无规矩不成方圆嘛。
HyperText:超文本,在电脑中显示的含有可以指向其它文本链接的文本;Hyper意为扩展。例如:HTML。 - HTTP的工作方式(简单讲解):浏览器输入地址回车发起请求->服务器处理请求->返回响应网页->浏览器内核进行网页渲染。
1. 先从看的到的入手——Url
举个例子:https://www.baidu.com/s?wd=nihao
- 其中
https
为协议类型,例如什么rtmp,http这些都是应用层协议。 -
www.baidu.com
为服务器地址, - 后面的
s?wd=nihao
为路径(Path)
2. URL到HTTP报文的转变
拿上面这个url例子来说,将会变成如下报文:
GET /s?wd=nihao HTTP/2.0
Host: www.baidu.com
3. Request的报文格式
GET /s?wd=nihao HTTP/2.0 —— 请求行(Request Line)
方法(method) 路径(Path) HTTP版本(version)
Host: www.baidu.com |
Content-Type: text/html | Headers(键值对)
Content-Length: 243 |
bodybodybodybodybody —— Body(注意Get请求方式是没有Body的,这里只是举例说明。所以Get的参数只要放入路径Path中就好)
4. Response的报文格式
5. 报文格式的解读
Request Method(请求方法):
- GET(查):获取资源,没有请求体(Body)
- POST(增或改):增加或者修改资源,Restful里面倾向于增加,有请求体(Body)
- PUT(改):修改资源,有请求体(Body)
- DELETE(删):删除资源,没有请求体(Body)
- HEAD:与GET几乎一致,但是不同的是,服务器不会返回Body。用处在哪儿?例如准备下载文件,我们想知道文件大小,支不支持断点续传,支不支持多线程下载等信息可以通过这个请求获得。
(小知识点:GET和PUT有一个"幂等"共性,大意就是这两种请求方式请求多次和请求一次结果都会是一样。例如同一个GET请求或取一个资源多次和获取一次结果都是一样,同一个PUT请求修改资源多次和修改一次也是一样。
)
状态码(status code)部分解析:
- 作用:对结果进行类型化描述,例如获取成功,内容未找到。
- 1xx(临时性消息系列状态码)
100 (继续)请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。场景:客户端向服务端传递大文件分段传输,传完一段服务器不用急着给我们响应,因为后面还有东西要传。做法:在请求头中添加一个额外的header表示后续还有东西要上传,最终最后一个上传时不添加这个额外的Header表示后面没有东西要上传啦,服务器假如全部接收成功,最终返回200状态码。
101 (切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。 - 2xx(成功系列状态码)
200 成功
201 创建成功 - 3xx(重定向系列状态码)
301 原有资源失效,已经永久性迁移
302 原有资源失效,暂时性迁移(例如页面有点小错误,暂时将用户引导到另一个界面)
304 资源未改变,因此服务器不会返回内容 - 4xx(客户端错误系列状态码)
404 资源找不到
400 客户端请求有问题(例如参数不对,请求方式不对)
401 未登录(未授权)
403 禁止,服务器拒绝此次请求 - 5xx(服务端错误系列状态码)
500 服务器内部错误,无法完成此次请求
505(HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。
Header解析:
- 作用:HTTP消息的元数据(metadata),类似于数据的属性。例如:内容长度,内容类型,字符编码等。
- Host:服务器主机地址,通过这个到域名系统(DNS)拿到服务器的ip地址。虽然不通过这个寻址,但是在访问服务器时还是要将这个Header交给服务器。原因是这个ip地址下可能还有多个(虚拟)主机,因此将这个header交给服务器的时候服务器才能给你引导到某个(虚拟)主机。
- Content-Length:内容的长度(字节),作用告诉对方这个内容有这么长,只有读取到这个长度才代表读取完了。
- Content-Type(内容类型),重点!!!:
- text/html; charset=utf-8:html文本,用于浏览器渲染界面
- application/x-www-form-urlencoded:普通表单,encoded URL格式,无法传输二进制内容。参数放在body中,参数格式有点像GET那些加在地址栏中的参数格式,同样也会进行url编码,例如汉字转换成%开头的一串字符。
歪门邪道:通过文件转Base64的方法,利用这种内容类型上传文件,效率太低,费空间!
- multipart/form-data:多部分形式,一般用于传输包含二进制内容的多项内容(用来传输纯文本就有点浪费空间)。一般这个后面还会携带一个boundary,代表body内容的分界线。例如:
multipart/form-data; boundary=----WebKitFormBoundarynQxIHiWrgD3eMUQx
。这里的内容分界线就是=号之后的字符串。有了这个字符串进行分隔,就知道每一段键值对。问题来了,那么二进制文件中刚好有这么一截字符串和这个分隔字符串相同咋办?这个交给了浏览器或者网络请求库,他们来保证这个字符串不会被二进制文件包含。报文示例如下(其中通过分隔出现了两个键值对,第一个键名称为name值为rengwuxian;第二个键名称为avatar值是一张jpg图片,显示出来的是二进制,这个还指定了内容类型为image/jpeg): -
application/json; charset=utf-8:json形式,用于Web Api的POST/PUT请求或者响应,报文示例如下:
-
image/jpeg , application/zip...:单文件提交形式,用于Web Api的响应或者POST/PUT的请求。最有效率的一种文件上传形式,但是却没啥人用,可悲!对应Retrofit的接口写法以及对应的报文示例如下:
@POST("user/{id}/avatar") public void uploadAvatar(@Path("id") String id, @Body RequestBody file); RequestBody avatarBody = RequestBody.create(MediaType.parse("image/jpeg"), avatarFile); api.uploadAvatar(id, avatarBody);
- Transfer-Encoding: chunked:场景,你请求服务器,但是数据太多,服务器不能一次性响应完成,但是为了用户体验,先拿到的资源就先返回给客户端,所以服务器无法确定Body内容的长度,自然Content-Length就无法使用了。但是客户端怎么知道服务器已经全部传完了呢?那就以一个固定的字符结尾,如果出现了这个字符,就标志着服务端已经将所有数据传递完毕。这种情况下解析body的做法和普通解析body的做法是一样的,没有什么特殊处理。这时候的Body格式以及报文格式如下所示:
<length1> 第一段数据的长度(同样还是必须告知一下这一段数据的长度,不然客户端不知道读取多少长度第一段数据才算结束) <data1> 第一段数据 <length2> 第二段数据的长度 <data2> 第二段数据 0 最后传输0加换行表示此次传输完成
- Location:重定向目标的URL。OKHttp会自动处理这个重定向,跳转到对应URL进行请求。如果你不需要这项功能可以关闭,自己进行自定义操作。
- User-Agent:用户代理,一般浏览器或者网络请求库会自动设置。标志着用户用什么东西请求的。
- Range / Accept-Range:指定Body的内容范围(例如一张图片通过设置这个header可以实现图片只下载一半,一般支持分段下载的网站才有这个header),用处在于断点续传、多线程下载等
- Cookie / Set-Cookie:发送Cookie / 设置Cookie,用处一般是授权
- Authorization:授权信息
- Accept:客户端能接收的数据类型。如:text/html
- Accept-Charset:客户端能接收的字符集。如:utf-8
- Accept-Encoding:客户端能接收的压缩编码类型。如:gzip
- Content-Encoding:压缩类型。如:gzip
- Cache相关:缓存,类似于我现在用完了,但是待会儿可能还会用,先放一边,后面再要用的时候直接拿,速度就会更快。与Buffer的区别是Buffer是缓冲,就像你在线看视频,视频从网络上加载(生产)与你实时观看(消费)的这一过程,生产出来先存下来的就是缓冲。Cache-Control:no-cache(你可以缓存,但你下次再使用之前要来问问服务器这个资源失效没有)、no-store(不要缓存)、max-age(定了一个失效日期,没超过失效日期你就可以直接用,否则重新来服务器取)、private(私有的,告诉中间节点,这是私有数据,不要缓存。这种数据不保密,只是个性信息)、public(公开的,公用的一些资源,告诉中间节点这个可以缓存)
- Last-Modified:这个资源最近一次是什么时候改变的。If-Modified-Since:是否在什么时间之后改过
- Etag:相当于一个资源的Hash。作用在于与现有资源比对一下,不一样肯定不是同一个资源,或者说现有资源在服务器中不是最新的。If-None-Match:如果不匹配,那么就去请求最新的资源
6. REST风格
rest只是一种架构,不仅仅是针对HTTP,但是是从HTTP开始。针对HTTP的REST应该遵循以下几点:
- CS架构(客户端服务端)
- 无状态:服务端只允许拿客户端提供的值来进行数据获取然后返回,本身自己并不保存任何状态。举个例子:第一次客户端用户登录,服务端并不保存用户登录了这个状态(但是能返回一些token啊什么的作为登录了的依据),第二次客户端想要这个登陆了的用户隐私信息,然而在没有携带任何身份证明的情况下服务器只能告诉客户端你没登录不能查看(因为客户端登录的时候服务端并不保留登录状态),只有客户端携带身份认证信息请求后才能继续。也就是每个请求之间是没有关联的。
- 可缓存
- 分层系统:个人理解,可能有误(即使后台并不只是一台服务器,可能是服务器集群,但是对外保证统一,也就是一个请求接口地址就可以正常使用所有API)
- 等等。。。(不说了,其实都不统一)
7. RESTful HTTP是什么?
- RESTful是REST风格设计
- 正确使用HTTP就是RESTful。
- 什么是正确使用HTTP?获取资源用GET请求,删除资源用DELETE请求,增加用POST请求等
小结
- HTTP到底是什么?是超文本传输协议,是协议!
- HTTP的工作模型:客户端按需求组装HTTP报文发送给服务器,服务器拿到报文后开始处理,处理好后组装成响应报文返回给客户端,客户端最后处理响应报文。
- 请求报文的大体格式:请求行、Headers、Body
- 请求行:Method、Path、HTTP version
- Method:PUT、DELETE、GET等
- Headers:请求的meta data(元数据)
- Body:要发送给服务器的内容
- 请求行:Method、Path、HTTP version
- 响应报文大体格式:响应行、Headers、Body
- 状态行:HTTP version、Status Code、Status Message
- Status Code:1xx(信息)、2xx(成功)、3xx(重定向)、4xx(客户端错误)、5xx(服务端错误)
- Headers:Host、Content-Type、Content-Length、Location、User-Agent、Range / Accept-Range
- Content-Type:text/html、application/json、application/x-www-form-urlencoded、image/jpeg、application/zip、multipart/form-data
- Chunked Transfer Encoding:
Transfer-Encoding: chunked
- 状态行:HTTP version、Status Code、Status Message
- 其他Header:Accept、Accept-Charset、Accept-Encoding、Content-Encoding
- Cache:Cache和Buffer的区别,和Cache相关的几个Header