HTTP 的概念、原理、⼯作机制、数据格式

前段时间去大佬何红辉(Android设计模式作者)的公司面试,前两轮还算顺利。等面到大佬的时候完全就是被虐的节奏。有些知识你觉得掌握自己掌握了,但是一些细节推敲起来你会发现自己掌握的那些还是没有get到点子上。所以说学知识一定要带着问题去学,并思考开发者为什么要这样设计。学到的这些知识一定要系统的总结一下,一个很好的方案就是在Xmind中画一个草图,方便自己记忆和理解。

就拿今天咱们研究的这个http来说,可以带着如下几个问题去探索一下:

  1. http到底是什么。
  2. Request由几个部分组成,每部分都有什么作用,Respose呢?
  3. 你了解Respose的返回码,通常都表示什么?

HTTP 的定义

http给咱们最直观的印象就是在浏览器的地址栏中输入一个网址,然后点击回车就跳转到了一个新的网页。
还有就是对于咱们android开发来说,在自己的app中发送了一个网络请求然后获取到响应内容。

HTTP的定义

Hypertext Transfer Protocol,超⽂本传输协议,和 HTML (Hypertext Markup Language 超⽂本标记语⾔言) ⼀一起诞生,用于在⽹络上请求和传输 HTML 内容。

超文本,即「扩展型文本」,指的是 HTML 中可以有链向别的⽂本的链接 (hyperlink)。超链接和超文本是一个意思。

协议的意思又是啥呢

其实协议就是通信双方约定好的,必须共同遵从的一组规则。如,怎样建立链接,怎样相互识别。

html相信大家都不陌生,这里贴个图,不过多讲解了。

在这里插入图片描述

1. HTTP 的工作方式

1.1 浏览器:

用户输入地址后回车或点击链接 ->
浏览器拼装 HTTP 报文并发送请求给服务器 ->
服务器处理理请求后发送响应报文给浏览器 ->
浏览器解析响应报文并使用渲染引擎显示 到界⾯面

1.2 手机 App:

在这里插入图片描述
用户点击或界⾯面⾃自动触发联⽹网需求 ->
Android 代码调⽤拼装 HTTP 报文并发送请求到服务器 ->
服务器处理请求后发送响应报⽂给手机 ->
Android 代码处理响应报文并作出相应处理(如储存数据、加工数据、显示数据到界⾯面)

2. URL 和 HTTP 报文

2.1 URL 格式

URL由三部分组成,包括

  • 协议类型
  • 服务器地址(和端口号)
  • 路径(Path)

协议类型:// 服务器地址[:端⼝号] 路径

具体格式

http://hencoder.com/users?gender=male

分别对应上面的协议类型、服务器地址和路径

2.2 报文格式

请求报⽂

格式如下图:
在这里插入图片描述
包括:请求行、Headers、Body(请求体,不是必须的)

  • 请求行:图中的 GET 对应的是请求方式,/users 表示的的要访问的路径,和Host:api.github.com 不同。HTTP/1.1 表示的是当前 http 协议对应的版本,目前大多数浏览器使用的是 1.1版本,很多已经开始向2.0发展。
  • Headers:下面会详细讲。
  • Body:请求体,不是必须的,可以放一些请求的参数。用来存放服务器要处理的数据,而不是定位的数据。

响应报文
格式如下图:

在这里插入图片描述
包括:状态行、Headers、Body

  • 状态行:包括 http 的使用版本,状态码和返回的状态信息。
  • Headers
  • Body:返回的信息放在 body 里面。

3. Request Method 请求方法

3.1 Get方式

http 0.9的唯一的一个请求方式。

  • 用于获取资源
  • 对服务器数据不会进行修改
  • 不发送Body
GET  /users/1  HTTP/1.1
Host: api.github.com

对应 Retrofit 的代码


@GET("/users/{id}")
Call<User> getUser(@Path("id") String id, @Query("gender") String gender);

3.2 Post方式
  • 用于增加或者修改资源
  • 发送给服务器的内容写在Body里面
POST  /users  HTTP/1.1
Host: api.github.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 13
name=rengwuxian&gender=male

对应 Retrofit 的代码


@FormUrlEncoded
@POST("/users")
Call<User> addUser(@Field("name") String name, @Field("gender") String gender);

3.3 Put方式
  • 用于修改资源
  • 发送给服务器的内容写在Body里面
  • 在修改功能上和 post 的区别在于 put 是幂等操作(幂等:多次调用和一次调用的结果相同,比如说修改一个用户的性别为女,改一次是女,改多次还是女,所以 Get 也是幂等)。
PUT  /users/1  HTTP/1.1
Host: api.github.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 13

gender=female

对应 Retrofit 的代码


@FormUrlEncoded
@PUT("/users/{id}")
Call<User> updateUser(@Path("id") String id, @Field("gender") String gender);

3.4 Delete方式
  • 用于删除资源
  • 不发送Body
DELETE  /users/1  HTTP/1.1
Host: api.github.com

@DELETE("/users/{id}")
Call<User> getUser(@Path("id") String id, @Query("gender") String gender);

3.5 Head方式
  • 和 Get 使用方法完全相同
  • 和 Get 唯一区别在于,返回的响应中没有 Body

这个不太常见,没有 Body 体,一般用在下载文件的时候先进行一次获取文件大小的操作,由于没有响应没有 Body,数据可以放在 Headers 里面。

4. Status Code 状态码

状态码是一个由三位数字组成的一个数据序列,主要用来对结果做出类型化描述。
如:「获取成功」、「内容未找到」。

基本内容如下表

编码表示内容举例
1xx临时性消息。如:100 (数据过大,分批发送时:继续发送,对应的Header:Expect:100-continue)、101(正在切换协议)
2xx成功。最典型的是 200(OK)、201(创建成功)。
3xx重定向。如 301(永久迁移)、302(暂时迁移)、304(内容未改变)。
4xx客户端错误。如 400(客户端请求错误,如,请求了一个不存在的页面)、401(认证失败)、403(被禁止)、404(找不不到内容)。
5xx服务器器错误。如 500(服务器器内部错误)。

最常用是2xx系列。所有2xx系列代表的都是成功。

然后是4xx系列,表示客户端错误。

5xx表示的表示服务器端出错了,方便程序员调试。

3xx系列表示重定向
301 永久迁移:如 http 转 https,浏览器直接做跳转。
302 暂时迁移:会保持权重,稍后可能会迁过来了

1xx系列:临时性消息
101(正在切换协议)比如从http 1.1升级到 2.0(Upgrade:h2c)。
100 (数据过大,分批发送时:继续发送,对应的Header:Expect:100-continue)

5. Header 首部

作用:HTTP 消息的 metadata。什么是metadata,就是元数据,通俗来讲就是关于数据的数据或者说数数据内部的数据,对核心数据起到辅助作用,比如说这个数据有多长,是什么格式…

5.1 Host

目标主机。注意:不是在网络上用于寻址的,而是在目标服务器上用于定位子服务器的。
一个IP可以对应多个域名,然后主主机再根据 Host 把数据转到子主机上。

5.2 Content-Type

指定 Body 的类型。主要有四类:

1. text/html

请求 Web 页面是返回响应的类型,Body 中返回 html 文本。格式如下:

HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 853

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
......
2. x-www-form-urlencoded

普通表单,Web 页面纯文本表单的提交方式,encoded URL 格式。

在这里插入图片描述
在这里插入图片描述
格式如下

POST  /users  HTTP/1.1
Host: api.github.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 27

name=rengwuxian&gender=male

对应 Retrofit 的代码:FormUrlEncoded 表示普通表单,用 Field 拼接参数。


@FormUrlEncoded
//用url拼成字符串放到body里面
@POST("/users")
Call<User> addUser(@Field("name") String name, @Field("gender") String gender);

3. multipart/form-data

Web 页面含有二进制文件时的提交方式。

在这里插入图片描述
在这里插入图片描述

格式如下:boundary 是用来做分界的,不同的部分用 boundary 来做显示的划分。以“–”加上 boundary 来做分割,最后一个 boundary 的末尾加上“–”。普通表单可以直接使用一个符号来做分割,multipart 可以传二进制格式所以不能用一个特定的符号来做分割,否则会造成混淆。

POST	/users	HTTP/1.1 
Host: hencoder.com
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW 
Content-Length: 2382

------WebKitFormBoundary7MA4YWxkTrZu0gW 
Content-Disposition: form-data; name="name"

rengwuxian
------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; name="avatar"; filename="avatar.jpg"
Content-Type: image/jpeg


JFIFHHvOwX9jximQrWa......
------WebKitFormBoundary7MA4YWxkTrZu0gW--

对应 Retrofit 的代码:


@Multipart
@POST("/users")
Call<User> addUser(@Part("name") RequestBody name, @Part("gender") RequestBody avatar);

//使用
RequestBody namePart = RequestBody.create(MediaType.parse("text/plain"), nameStr);
RequestBody avatarPart = RequestBody.create(MediaType.parse("image/jpeg"), avatarFile);
api.addUser(namePart,avatarPart);

4. application/json , image/jpeg , application/zip …

单项内容(文本或非文本都可以),用于 Web Api 的响应或者 POST / PUT 的请求

application/json:json格式,用于 Web Api 的响应或 POST/PUT 请求。

请求中提交 JSON

POST /users HTTP/1.1
Host: hencoder.com
Content-Type: application/json; charset=utf-8
Content-Length: 38

{"name":"rengwuxian","gender":"male"}

对应 Retrofit 的代码:


@POST("/users")
Call<User> addUser(@Body("user") User user);
...
//使用 需要使用 Json 相关的 Converter
api.addUser(user);

响应中返回 JSON

HTTP/1.1 200 OK
content-type: application/json; charset=utf-8
content-length: 234
[{"login":"mojombo","id":1,"node_id":"MDQ6VXNl
cjE=","avatar_url":"https://avatars0.githubuse
rcontent.com/u/1?v=4","gravat......

image/jpeg:上传图片和下载图片。

请求中提交二进制内容

POST /user/1/avatar HTTP/1.1
Host: hencoder.com
Content-Type: image/jpeg
Content-Length: 1575

JFIFHH9......

对应 Retrofit 的代码:

@POST("users/{id}/avatar")
Call<User> updateAvatar(@Path("id") String id, @Body RequestBody avatar);

...

RequestBody avatarBody = RequestBody.create(MediaType.parse("image/jpeg"),avatarFile);
api.updateAvatar(id, avatarBody)

响应中返回二进制内容

HTTP/1.1 200 OK
content-type: image/jpeg
content-length: 1575

JFIFHH9......
5.2 Content-Length

指定 Body 的长度(字节)。

5.3 Transfer: chunked (分块传输编码 Chunked Transfer Encoding)

用于当响应发起时,Body 长度还没能确定的情况下,服务端告诉客户端,我的数据要分块传输。和 Content-Length 不同时使用。它的用途是尽早给出响应,减少用户等待。

Body 的格式:最后传输 0 表示内容结束

<length1>
<data1>
<length2>
<data2>
0

具体格式:

HTTP/1.1 200 OK
Content-Type: text/html
Transfer-Encoding: chunked

4
Chun
9
ked Trans
12
fer Encoding
0

5.4 Location

指定重定向的目标 URL。在访问 http://hencoder.com 的时候,可以在控制台中 Status Code 为 3xx 的日志看到 Location。
在这里插入图片描述

5.5 User-Agent

用户代理,即是谁实际发送请求、接受响应的,例如手机浏览器、某款手机 App。

user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
5.6 Range / Accept-Range

表示可以按范围取数据

Accept-Range: bytes 响应报文中出现,表示服务器⽀持按字节来取范围数据
Range: bytes=- 请求报文中出现,表示要取哪段数据
Content-Range:-/total 响应报⽂中出现,表示发送的是哪段数据

作用:

断点续传、多线程下载。

5.7 其他 Headers
  • Accept: 客户端能接受的数据类型。如 text/html
  • Accept-Charset: 客户端接受的字符集。如 utf-8
  • Accept-Encoding: 客户端接受的压缩编码类型。如 gzip
  • Content-Encoding:压缩类型。如 gzip
5.8 Cache

cache和buffer的区别

  • cache:缓存,我这会用完了可能还要用,先存一下备用
  • buffer:缓冲,上游多生产了一些给下游稍后用。

Cache-Control:
no-cache、no-store、max-age

  • no-cache:不是不能缓存,下次请求时要先询问缓存是否有效。如果存在合适的验证令牌 (ETag),no-cache 会发起往返通信来验证缓存的响应,但如果资源未发生变化,则可避免下载
  • no-store:禁止浏览器以及所有中间缓存存储任何版本的返回响应。
  • private:私有缓存,这里不做过多解释。
  • public:公有缓存,这里不做过多解释。

作用:
在客户端或中间网络节点缓存数据,降低从服务器取数据的频率,以提高网络性能。

6. REST

REST 的定义众说纷纭,没有统一答案。
扔物线的观点:REST HTTP 即正确使用 HTTP。包括: 使用资源的格式来定义 URL

完结。

感谢朱凯老师提供的视频教学。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值