HTTP
报文结构是怎样的
对于 TCP 而言,在传输的时候分为两个部分:TCP头和数据部分。
而 HTTP 类似,也是header + body
的结构,具体而言:
起始行 + 头部 + 空行 + 实体
由于 http
请求报文
和响应报文
是有一定区别,因此我们分开介绍。
起始行
对于请求报文来说,起始行类似下面这样:
GET /home HTTP/1.1
也就是方法 + 路径 + http
版本。
对于响应报文来说,起始行一般张这个样:
HTTP/1.1 200 OK
响应报文的起始行也叫做状态行
。由http
版本、状态码和原因三部分组成。
值得注意的是,在起始行中,每两个部分之间用空格隔开,最后一个部分后面应该接一个换行,严格遵循ABNF
语法规范。
头部
分两种:
① 请求行 + 请求头 + 空行
② 状态行 + 响应头 + 空行
两种头部字段的格式都是:
字段名不区分大小写
字段名不允许出现空格,不可以出现下划线_
字段名后面必须紧接着:
空行
用来区分头部和实体。
要是在头部故意加个空行会怎样?
空行后面的内容都会被看成实体。
实体
具体数据,body
部分。请求报文对应请求体,响应报文对应响应体。
HTTP 的请求方法
http/1.1
都有什么方法:
- GET:通常用来获取资源
- HEAD:获取资源的元信息
- POST:提交数据,即上传数据
- PUT:修改数据
- DELETE:删除资源(几乎用不到)
- CONNECT:建立连接隧道,用于代理服务器
- OPTIONS:列出可对资源实行的请求方法,用来跨域请求
- TRACE:追踪请求-响应的传输路径
GET 和 POST 有什么区别
- 从缓存的角度,GET 请求会被浏览器主动缓存下来,留下历史记录,而 POST 默认不会。
- 从编码的角度,GET 只能进行 URL 编码,只能接收 ASCII 字符,而 POST 没有限制。
- 从参数的角度,GET 一般放在 URL 中,因此不安全,POST 放在请求体中,更适合传输敏感信息。
- 从幂等性的角度,
GET
是幂等的,而POST
不是。(幂等
表示执行相同的操作,结果也是相同的) - 从TCP的角度,GET 请求会把请求报文一次性发出去,而 POST 会分为两个 TCP 数据包,首先发 header 部分,如果服务器响应 100(continue), 然后发 body 部分。(火狐浏览器除外,它的 POST 请求只发一个 TCP 包)
如何理解 URI
Uniform Resource Identifier (统一资源标识符),用来区分互联网上不同的资源。
它不是真正意义上的网址,网址指的是URL
,实际上RUI
包含了URN
和URL
两个部分,由于URL
过于普及,就默认讲URI
视为URL
了。
URI结构
scheme
+ :/
+ user:passwd@
+ host:port
+ path
+ ?query
+ #fragment
scheme
:表示协议名,比如http
, https
, file
等等。后面必须和://
连在一起。
user:passwd@
:表示登录主机时的用户信息,不过很不安全,不推荐使用,也不常用。
host:port
:表示主机名和端口。
path
:表示请求路径,标记资源所在位置。
?query
:表示查询参数,为key=val
这种形式,多个键值对之间用&
隔开。
#fragment
:表示 URI 所定位的资源内的一个锚点,浏览器可以根据这个锚点跳转到对应的位置。
URI编码
URI 只能使用ASCII
, ASCII 之外的字符是不支持显示的,而且还有一部分符号是界定符,如果不加以处理就会导致解析出错。
因此,URI 引入了编码
机制,将所有非 ASCII 码字符和界定符转为十六进制字节值,然后在前面加个%
。
HTTP状态码
RFC 规定 HTTP 的状态码为三位数,被分为五类:
1xx
: 表示目前是协议处理的中间状态,还需要后续操作。2xx
: 表示成功状态。3xx
: 重定向状态,资源位置发生变动,需要重新请求。4xx
: 请求报文有误。5xx
: 服务器端发生错误。
个人常见
404 Not Found:资源未找到
HTTP 特点及缺点
特点
- 灵活可扩展,主要体现在两个方面。一个是语义上的自由,只规定了基本格式,比如空格分隔单词,换行分隔字段,其他的各个部分都没有严格的语法限制。另一个是传输形式的多样性,不仅仅可以传输文本,还能传输图片、视频等任意数据,非常方便。
- 可靠传输。
HTTP
基于TCP/IP
,因此把这一特性继承了下来。这属于TCP
的特性,不具体介绍了。 - 请求-应答。也就是
一发一收
、有来有回
, 当然这个请求方和应答方不单单指客户端和服务器之间,如果某台服务器作为代理来连接后端的服务端,那么这台服务器也会扮演请求方的角色。 - 无状态。这里的状态是指通信过程的上下文信息,而每次
http
请求都是独立、无关的,默认不需要保留状态信息。
缺点
-
无状态。
还是得分场景看。在需要长连接(个人理解:
tcp
连接保持一阶段不关闭。)的场景中,需要保存大量的上下文信息,以免传输大量重复的信息,这时候是缺点。但是,另外一些应用仅仅只为了获取一些数据,不需要保存连接上下文信息,无状态反而减少了网络开销,成为了http
的优点。 -
明文传输。
这当然对于调试提供了便利,但同时也让 HTTP 的报文信息暴露给了外界,给攻击者也提供了便利。
WIFI陷阱
就是利用 HTTP 明文传输的缺点,诱导你连上热点,然后疯狂抓你所有的流量,从而拿到你的敏感信息。 -
队头阻塞
当
http
开启长连接时,共用一个 TCP 连接,同一时刻只能处理一个请求,那么当前请求耗时过长的情况下,其它的请求只能处于阻塞状态,也就是著名的队头阻塞问题。
Content系列字段了解
四个部分: 数据格式、压缩方式、支持语言、字符集。
数据格式
HTTP 从MIME type取了一部分来标记报文 body 部分的数据类型,这些类型体现在Content-Type
这个字段,这是针对于发送端而言,接收端想要收到特定类型的数据,也可以用Accept
字段。
这两个字段的取值可以分为下面几类:
-
文本
text: text/html, text/plain, text/css
等 -
图片
image: image/gif, image/jpeg, image/png
等 -
音频
audio/video: audio/mpeg, video/mp4
等 -
代码
application: application/json,
application/javascript,
application/pdf,
application/octet-stream
压缩方式
采取什么样的压缩方式就体现在了发送方的Content-Encoding
字段上, 同样的,接收什么样的压缩方式体现在了接受方的Accept-Encoding
字段上。这个字段的取值有下面几种:
gzip:
当今最流行的压缩格式deflate:
另外一种著名的压缩格式br:
一种专门为 HTTP 发明的压缩算法
// 发送端
Content-Encoding: gzip
// 接收端
Accept-Encoding: gizp
支持语言
对于发送方而言,还有一个Content-Language
字段,在需要实现国际化的方案当中,可以用来指定支持的语言,在接受方对应的字段为Accept-Language
。如:
// 发送端
Content-Language: zh-CN, zh, en
// 接收端
Accept-Language: zh-CN, zh, en
字符集
最后是一个比较特殊的字段, 在接收端对应为Accept-Charset
,指定可以接受的字符集,在发送端并没有对应的Content-Charset
, 而是直接放在了Content-Type
中,以charset
属性指定。如:
// 发送端
Content-Type: text/html; charset=utf-8
// 接收端
Accept-Charset: charset=utf-8