HTTP发展史
让我们通过下面这张图简单了解一下HTTP协议的发展史~
点击可查看世界上第一个网站:世界上第一个网站
简单说明一下HTTP和HTTPS的区别:(不具体展开)
HTTPS 的安全性是由 TLS 来保证,它为 HTTP 增加了机密性、完整性,身份认证和不可否认等特性。
HTTP—超文本传输协议
HTTP 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范。
HTTP传输的报文(HTTP的核心部分)
HTTP 协议的请求报文和响应报文的结构
- 起始行(start line):描述请求或响应的基本信息;
- 头部字段集合(header):使用 key-value 形式更详细地说明报文;
- 消息正文(entity):实际传输的数据,它不一定是纯文本,可以是图片、视频等二进制数据。
注意:
- HTTP 协议规定报文必须有 header,但可以没有 body,而且在 header 之后必须要有一个“空行”,也就是“CRLF”,十六进制的“0D0A”。
- 虽然 HTTP 协议对 header 的大小没有做限制,但各个 Web 服务器都不允许过大的请求头,因为头部太大可能会占用大量的服务器资源,影响运行效率。
接下来我们先分开看一下“请求行”和"响应行"
请求行
eg: GET / HTTP/1.1
- 请求方法:是一个动词,如 GET/POST,表示对资源的操作;
- 请求目标:通常是一个 URI,标记了请求方法要操作的资源;
- 版本号:表示报文使用的 HTTP 协议版本。
状态行
eg: HTTP/1.1 200 OK
- 版本号:表示报文使用的 HTTP 协议版本;
- 状态码:一个三位数,用代码的形式表示处理的结果,比如 200 是成功,500 是服务器错误;
- 原因:作为数字状态码补充,是更详细的解释文字,帮助人理解原因。
已上是对HTTP报文结构中的“起始行”的结构的了解,让我们接下来来看一下“头部字段”吧~
头部字段
HTTP报文头部字段是 key-value 的形式,key 和 value 之间用“:”分隔,最后用 CRLF 换行表示字段结束;
除了使用标准里的 Host、Connection 等已有头,也可以任意添加自定义头,这给 HTTP 协议带来了扩展可能。
注意:
- 字段名不区分大小写,例如“Host”也可以写成“host”,但首字母大写的可读性更好;
- 字段名里不允许出现空格,可以使用连字符“-”,但不能使用下划线“_”。例如,“test-name”是合法的字段名,而“test name”“test_name”是不正确的字段名;
- 字段的顺序是没有意义的,可以任意排列不影响语义;
- 字段原则上不能重复,除非这个字段本身的语义允许,例如 Set-Cookie;
- 字段名后面必须紧接着“:”,不能有空格,而“:”后的字段值前可以有多个空格;如果字段名前面,也就是“:”前面有空格,请求会报错,如:
HTTP/1.1 400 Bad Request
Server: openresty/1.15.8.1
Connection: close
常用头字段
头部字段的类型
| 类型 | 说明 |
|---|---|
| 通用字段 | 在请求头和响应头里都可以出现 |
| 请求字段 | 仅能出现在请求头里,进一步说明请求信息或者额外的附加条件 |
| 响应字段 | 仅能出现在响应头里,补充说明响应报文的信息 |
| 实体字段 | 它实际上属于通用字段,但专门描述 body 的额外信息 |
几个基本的头部字段
| 字段名 | 类型 | 说明 |
|---|---|---|
| Host | 请求字段 | 是唯一一个 HTTP/1.1 规范里要求必须出现的字段 |
| User-Agent | 请求字段 | 它使用一个字符串来描述发起 HTTP 请求的客户端,服务器可以依据它来返回最合适此浏览器显示的页面 |
| Date | 通用字段 | 通常出现在响应头里,表示 HTTP 报文创建的时间,客户端可以使用这个时间再搭配其他字段决定缓存策略 |
| Server | 响应字段 | 告诉客户端当前正在提供 Web 服务的软件名称和版本号;Server 字段也不是必须要出现的,因为这会把服务器的一部分信息暴露给外界,如果这个版本恰好存在 bug,那么黑客就有可能利用 bug 攻陷服务器。所以,有的网站响应头里要么没有这个字段,要么就给出一个完全无关的描述信息 |
| Content-Length | 实体字段 | 表示报文里 body 的长度,也就是请求头或响应头空行后面数据的长度。服务器看到这个字段,就知道了后续有多少数据,可以直接接收。如果没有这个字段,那么 body 就是不定长的,需要使用 chunked 方式分段传输。 |
接下来,让我们来看一下HTTP协议的请求方法
请求方法
请求方法的实际含义就是客户端发出了一个“动作指令”,要求服务器端对 URI 定位的资源执行这个动作。
既然是“指令”,也就是说客户端“要求”服务器要做什么,但是服务器实际上要怎么做,还是服务器说了算。
HTTP/1.1 规定了八种方法,单词都必须是大写的形式
| 方法名 | 含义 | 其它说明 |
|---|---|---|
| GET | 获取资源,可以理解为读取或者下载数据 | 资源既可以是静态的文本、页面、图片、视频,也可以是由 PHP、Java 动态生成的页面或者其他格式的数据;搭配 URI 和其他头字段就能实现对资源更精细的操作 |
| HEAD | 获取资源的元信息 | 请求从服务器获取资源,服务器的处理机制也是一样的,但服务器不会返回请求的实体数据,只会传回响应头,也就是资源的“元信息” |
| POST | 向资源提交数据,相当于写入或上传数据 | 通常 POST 表示的是“新建”“create”的含义 |
| PUT | 类似 POST | PUT 表示“修改”“update”的含义 |
| DELETE | 删除资源 | 指示服务器删除资源,因为这个动作危险性太大,所以通常服务器不会执行真正的删除操作,而是对资源做一个删除标记。当然,更多的时候服务器就直接不处理 DELETE 请求 |
| CONNECT | 建立特殊的连接隧道 | |
| OPTIONS | 列出可对资源实行的方法 | 要求服务器列出可对资源实行的操作方法,在响应头的 Allow 字段里返回。http跨域时的options请求Access-Control-Max-Age用来指定本次预检请求的有效期,单位为秒,,在此期间不用发出另一条预检请求。 |
| TRACE | 追踪请求 - 响应的传输路径 | 多用于对 HTTP 链路的测试或诊断,可以显示出请求 - 响应的传输路径。它的本意是好的,但存在漏洞,会泄漏网站的信息,所以 Web 服务器通常也是禁止使用。 |
请求方法的安全与幂等
安全:
在 HTTP 协议里,所谓的“安全”是指请求方法不会“破坏”服务器上的资源,即不会对服务器上的资源造成实质的修改。
按照这个定义, GET , HEAD,OPTIONS 方法是“安全”的,因为它们是“只读”操作,只要服务器按照规范处理请求方法,服务器上的数据都是“安全的”。
幂等:
HTTP方法的幂等性是指一次和多次请求某一个资源应该具有同样的副作用。
GET 和 HEAD 既是安全的也是幂等的,DELETE 可以多次删除同一个资源,效果都是“资源不存在”,所以也是幂等的。
POST 和 PUT 的幂等性质就略费解一点。
按照 RFC 里的语义,POST 是“新增或提交数据”,多次提交数据会创建多个资源,所以不是幂等的;而 PUT 是“替换或更新数据”,多次更新一个资源,效果都是“资源被更新”了,所以是幂等的。
如何理解幂等:
关于网址
相信每天的工作生活中我们都会接触到网址,我们常说:把地址发我一下,或是URL发我一下,那URL地址具体是什么样子的呢?
URI与URL
URI:统一资源标识符(Uniform Resource Identifier)
URI含有 URL 和 URN 两个部分,也就是说URL是URI的子集;
URI 本质上是一个字符串,这个字符串的作用是唯一地标记资源的位置或者名字。
不仅能够标记万维网的资源,也可以标记其他的,如邮件系统、本地文件系统等任意资源。
URL:统一资源定位符(Uniform Resource Locator)
在 HTTP 世界里用的网址实际上是 URL——统一资源定位符(Uniform Resource Locator)。
URN
URI的一种,用特定命名空间的名字标识资源。使用URN可以在不知道其网络位置及访问方式的情况下讨论资源。
URI的组成:(有的部分可以视情况省略)
常见的URI的组成:
完整的URI组成:
主要包含了以下几个部分
| 组成部分 | 说明 | 其他 |
|---|---|---|
| scheme | 协议名,表示资源应该使用哪种协议来访问。 | 最常见的当然就是“http”了,表示使用 HTTP 协议。另外还有“https”,表示使用经过加密、安全的 HTTPS 协议。此外还有其他不是很常见的 scheme,例如 ftp、ldap、file、news 等 |
| host:port | 资源所在的主机名,通常的形式是“host:port”,即主机名加端口号 | 主机名可以是 IP 地址或者域名的形式,必须要有,否则浏览器就会找不到服务器。但端口号有时可以省略,浏览器等客户端会依据 scheme 使用默认的端口号,例如 HTTP 的默认端口号是 80,HTTPS 的默认端口号是 443 |
| path | 标记资源所在位置 | URI 的 path 部分必须以“/”开始,也就是必须包含“/”,不要把“/”误认为属于前面 authority。 |
| query | 在 path 之后,用一个“?”开始,但不包含“?”,表示对资源附加的额外要求。 | 查询参数 query 的格式,是多个“key=value”的字符串,这些 KV 值用字符“&”连接,浏览器和服务器都可以按照这个格式把长串的查询参数解析成可理解的字典或关联数组形式。 |
| user:passwd@ | 表示登录主机时的用户名和密码 | 但现在已经不推荐使用这种形式了(RFC7230),因为它把敏感信息以明文形式暴露出来,存在严重的安全隐患。 |
| #fragment | 片段标识符;它是 URI 所定位的资源内部的一个“锚点”或者说是“标签”,浏览器可以在获取资源后直接跳转到它指示的位置。 | 但片段标识符仅能由浏览器这样的客户端使用,服务器是看不到的。也就是说,浏览器永远不会把带“#fragment”的 URI 发送给服务器,服务器也永远不会用这种方式去处理资源的片段。vue路由hash模式 |
一个常见又特殊的URI
当我们把本地的文件,比如一张本地的图片直接拖到浏览器打开时,浏览器上显示的地址格式是:
例子:file:///C:/Users/test/Desktop/HTTP/HTTP.npg
可以看到在协议名的后面居然有三个斜杠,是怎么回事呢?
这三个斜杠里的前两个属于 URI 特殊分隔符“://”,然后后面的“/C:/Users/linshuling/Desktop/HTTP/HTTP.npg”是路径,而中间的主机名被“省略”了。这实际上是 file 类型 URI 的“特例”,它允许省略主机名,默认是本机 localhost。
注意:
对于 HTTP 或 HTTPS 这样的网络通信协议,主机名是绝对不能省略的,会导致浏览器无法找到服务器。
URI 的编码
我们知道,在 URI 里只能使用 ASCII 码,但如果要在 URI 里使用英语以外的汉语、日语等其他语言,或者@&?"等起界定符作用的字符,会导致 URI 解析错误,这时就需要编码机制啦~
编码机制:
一般使用encodeURI, encodeURIComponent 对URI进行编码。
encodeURI, encodeURIComponent的区别和使用场景
状态行中的状态码
状态码的格式
RFC 标准规定的状态码是三位数,分成了五类,用数字的第一位表示分类,这样状态码的实际可用范围是100~599。
状态码的分类
| 状态码 | 说明 |
|---|---|
| 1×× | 提示信息,表示目前是协议处理的中间状态,还需要后续的操作 |
| 2×× | 成功,报文已经收到并被正确处理 |
| 3×× | 资源位置发生变动,需要客户端重新发送请求 |
| 4×× | 客户端错误,请求报文有误,服务器无法处理 |
| 5×× | 服务器错误,服务器在处理请求时内部发生了错误 |
常见的状态码
1xx
| 状态码 | 说明 |
|---|---|
| 101 Switching Protocols | 户端使用 Upgrade 头字段,要求在 HTTP 协议的基础上改成其他的协议继续通信,比如 WebSocket。而如果服务器也同意变更协议,就会发送状态码 101,但这之后的数据传输就不会再使用 HTTP 了。一个例子:websocket 链接返回 http 状态码 101 |
2xx
| 状态码 | 说明 |
|---|---|
| 200 Ok | |
| 204 No Content | 也是成功状态码,但响应头后没有 body 数据 |
3xx
| 状态码 | 说明 |
|---|---|
| 301 Moved Permanently | 永久重定向”,含义是此次请求的资源已经不存在了,需要改用新的 URI 再次访问。 |
| 302 Found | 临时重定向”,意思是请求的资源还在,但需要暂时用另一个 URI 来访问。 |
| 304 Not Modified | 用于 If-Modified-Since 等条件请求,表示资源未修改,用于缓存控制。 |
4xx
| 状态码 | 说明 |
|---|---|
| 400 Bad Request | 请求报文有错误。 |
| 403 Forbidden | 服务器禁止访问资源 |
| 404 Not Found | 资源在本服务器上未找到 |
| 405 Method Not Allowed | 不允许使用某些方法操作资源,例如不允许 POST 只能 GET |
| 406 Not Acceptable | 资源无法满足客户端请求的条件,例如请求中文但只有英文 |
| 408 Request Timeout | 请求超时,服务器等待了过长的时间 |
| 409 Conflict | 多个请求发生了冲突,可以理解为多线程并发时的竞态 |
| 413 Request Entity Too Large | 请求报文里的 body 太大 |
| 414 Request-URI Too Long | 请求行里的 URI 太大 |
| 429 Too Many Requests | 客户端发送了太多的请求,通常是由于服务器的限连策略 |
| 431 Request Header Fields Too Large | 请求头某个字段或总体太大 |
5xx
| 状态码 | 说明 | 其他 |
|---|---|---|
| 500 Internal Server Erro | 通用的错误码,服务器错误 | |
| 501 Not Implemented | 表示客户端请求的功能还不支持 | |
| 502 Bad Gateway | 通常是服务器作为网关或者代理时返回的错误码,表示服务器自身工作正常,访问后端服务器时发生了错误,但具体的错误原因也是不知道的 | |
| 503 Service Unavailable | 表示服务器当前很忙,暂时无法响应服务,我们上网时有时候遇到的“网络服务正忙,请稍后重试”的提示信息就是状态码 503 | 503 是一个“临时”的状态,很可能过几秒钟后服务器就不那么忙了,可以继续提供服务,所以 503 响应报文里通常还会有一个“Retry-After”字段,指示客户端可以在多久以后再次尝试发送请求 |
已上是关于HTTP协议的一些基础~