重新认识HTTP(一) | 青训营

82 阅读9分钟

重新认识HTTP(一)

在Web应用中,服务器把网页传给浏览器,实际上就是把网页的HTML代码发送给浏览器,让浏览器显示出来。而浏览器和服务器之间的传输协议是HTTP。可以说,我们浏览网页,下载资源,甚至克隆一个感兴趣的github仓库,都在与HTTP协议打交道。但是,在计算机网络课程和考研中HTTP都不作为重点去讲述,而在面试和实际工作中却经常需要接触。因此更深入的了解HTTP协议显得尤为重要。

为什么需要HTTP

正如HTTP叫做文本传输协议,大家都知道咱们的欲望是不能够很轻易的被满足的。那有了网络之后,大家就发现text已经没有办法满足我们大家对于传输的这样的一个需求了,那逐渐的我们就有了一些图片、音乐以及视频,甚至说还有一些超链接这样的一个需求,那这些资源他们针对是我们的text,是一个扩充,所以说它叫做 hypertypes,也就是超文本。那传输这种资源的协议,我们就把它叫做 HyperType Transfer Protocol了。

那在有了明确的边界之后,其实我们大家也能够想到,我们需要用元数据进行一个信息的描述,用来去描述这个信息它是什么类型的,就包括说我们刚刚看到的一些图片、音视频以及超链接这些东西,那这样之后我们就可以把这些东西就是具体的内容塞到一个他消息对应的地方。下面就详细介绍HTTP中关于元数据的一些细节。

HTTP请求方法

RESTful API这个词大概多多少少有所耳闻。RESTful(REST is REpresentational State Transfer)是目前最流行的接口设计规范,在很多公司有着广泛的应用。RESTful最核心的特点是URL定位资源,用HTTP动词(GET,POST,DELETE,DETC等)描述操作。 因此理解HTTP请求方法中原本的含义,有利于我们更好的理解资源管理的操作,设计良好的接口。

方法描述
GET请求指定的页面信息,并返回具体内容,通常只用于读取数据。
HEAD类似于 GET 请求,只不过返回的响应中没有具体的内容,用于获取报头。
POST向指定资源提交数据进行处理请求(例如提交表单或者上传文件),数据被包含在请求体中。
PUT替换指定的资源,没有的话就新增。
DELETE请求服务器删除 URL 标识的资源数据。
CONNECT将服务器作为代理,让服务器代替用户进行访问。
OPTIONS向服务器发送该方法,会返回对指定资源所支持的 HTTP 请求方法。
PATCH对 PUT 方法的补充,用来对已知资源进行局部更新。
TRACE回显服务器收到的请求数据,即服务器返回自己收到的数据,主要用于测试和诊断。

GET和POST大概是我们最常见到的请求方法了。下面对其区别进行深入探讨。

参数位置

我们对其最直观的感受,GET经常用来请求页面,参数放到urlpath里,而POST经常用来提交表单,参数放到body里。实际上这只是习惯的用法,从协议本身看,并没有什么限制说GET一定不能没有body,POST就一定不能把参放到<URL>querystring上。因此其实可以更加自由的去利用格式。比如Elastic Search_search api就用了带body的GET;也可以自己开发接口让POST一半的参数放在urlquerystring里,另外一半放body里;你甚至还可以让所有的参数都放Header里——可以做各种各样的定制,只要请求的客户端和服务器端能够约定好。如果用过Postman的话,也能感受到其实不管是什么方法都能自由的把数据填到任何位置(所以也会经常填错(笑))

另外,我们也知道url是有长度限制的。其实url 本身并没有对长度进行限制,但是浏览器会对 url 进行限制,比如 FireFox 限制 url 的最大长度为 65536 个字符,也就是 64KB的大小,而 Chrome 限制 url 最大长度为 8182个字符,也就是 8 KB 的大小。因此,url只要某个要开发的资源/api的URL长度特别长,就推荐使用body来传输数据,除非有特殊情况。因为过长的url即使忽略浏览器本身的限制,也不利于后续的项目维护,不利于搜索引擎的爬取等。

安全性

我们常听到GET不如POST安全,因为POST用body传输数据,而GET用url传输,更加容易看到。但是从攻击的角度,无论是GET还是POST都不够安全,因为HTTP本身是明文协议每个HTTP请求和返回的每个byte都会在网络上明文传播,不管是url,header还是body。这完全不是一个“是否容易在浏览器地址栏上看到“的问题。

为了避免传输中数据被窃取,必须做从客户端到服务器的端端加密。业界的通行做法就是https——即用SSL协议协商出的密钥加密明文的http数据。这个加密的协议和HTTP协议本身相互独立。如果是利用HTTP开发公网的站点/App,要保证安全,https是最最基本的要求。

回到HTTP本身,的确GET请求的参数更倾向于放在url上,因此有更多机会被泄漏。比如携带私密信息的url会展示在地址栏上,还可以分享给第三方,就非常不安全了。此外,从客户端到服务器端,有大量的中间节点,包括网关,代理等。他们的access log通常会输出完整的url,比如nginx的默认access log就是如此。如果url上携带敏感数据,就会被记录下来。但请注意 ,就算私密数据在body里,也是可以被记录下来的

当然,对于重要的数据,也可以在POST的body中再次对数据加密,对于GET的请求参数也可以采用一些方式进行处理,比如短url生成等,使链接便于传播(当然这解决不了安全问题)。但是最本质的安全策略还是HTTPS。另外,网络安全也是个非常深的话题,在这里单独拎出来讨论GET和POST的安全性问题,其实意义不是很大。

HTTP状态码

状态码类别含义
100 \sim 199信息性状态码接收的请求正在处理
200 \sim 299成功状态码请求正常处理完毕
300 \sim 399重定向状态码使用替代位置来访问
400 \sim 499客户端错误状态码服务器无法处理请求

比较常见的状态码:

200:成功返回响应 301:永久重定向,客户端第一次访问此 url 时,告知客户端以后直接访问新的 url,该状态保存在浏览器缓存中。 302;临时重定向,客户端每次访问此 url 时,告知客户端重定向到新的 url ,后续访问依然访问当前的 url。 400:发送的请求错误,请求格式错误,或者没有服务器要求的数据。 401:没有权限访问,当前用户没有权限访问此资源。 403: 请求被服务器禁止。 404:请求的 url 不存在,一般是 url 出错。 500: 服务器处理请求出现错误。 501:服务器超出能力之外的方法,例如:请求的方法服务器不支持。 504:来自网关或者代理服务器,请求资源服务器时超时。

HTTP首部

http 主要有 4 种类型的首部字段:通用首部字段、请求首部字段、响应首部字段和实体首部字段。除此之外,还有一种扩展首部,这种首部还未添加的 http 标准中去。在一些大型互联网公司内部,开发者需要特定的扩展首部来实现特殊的功能。

通用首部字段:请求和响应都可以使用的首部,与报文相关的最基本的信息。
请求首部字段:仅在请求中使用的首部。
响应首部字段:仅在响应中使用的首部。
实体首部字段:用于应对实体部分的首部,一般是对实体内容进行说明。

连接管理

HTTP/1.0缺省为非持久连接

  • 服务器接收请求、给出响应、关闭TCP连接

获取每个对象需要两阶段

  • 建立TCP连接
  • 对象请求和传输

每次连接需要经历TCP慢启动阶段

HTTP/1.1缺省为持久连接

  • 在相同的TCP连接上服务器接收请求、给出响应;再接收请求、 给出响应;响应后保持连接

HTTP/1.1支持流水线机制

  • 需要按序响应

经历较少的慢启动过程,减少往返时间

  • 降低响应时间

下面以客户端获取一个含有两个图片的网页为例说明比较HTTP1.0和HTTP1.1:

image-20230824222540738

总结

在这一部分,对HTTP的起源,以及HTTP请求和响应的最基本的内容进行介绍,特别是关于请求方法和状态码中的一些细节在面试和实际工作中有必要进行熟悉。后面将会继续介绍关于连接管理相关的内容,包括更细致的说明HTTP的发展过程,讲解实现在无连接协议之上保存状态的方式,以及HTTPS相关的内容。