简述HTTP协议

24次阅读

共计 7679 个字符,预计需要花费 20 分钟才能阅读完成。

身为开发人员除了应该对我们所写的项目需求要了解,以及基本的语言知识,对于 HTTP 协议应该也是应该了解一下的,因为这些东西与我们是密不可分的,每天都在和 HTTP 打交道然而却不知道它到底是什么?这样说出去是不是很可悲?简直可歌可泣有没有 …

http 协议:HTTP 是一个简单的请求 - 响应协议,它通常运行在 TCP 之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。请求和响应消息的头以 ASCII 码形式给出;而消息内容则具有一个类似 MIME 的格式。这个简单模型是早期 Web 成功的有功之臣,因为它使得开发和部署是那么的直截了当。超文本传输协议(HTTP)是用于传输诸如 HTML 的超媒体文档的应用层协议。它被设计用于 Web 浏览器和 Web 服务器之间的通信,但它也可以用于其他目的。HTTP遵循经典的客户端 - 服务端模型,客户端打开一个连接以发出请求,然后等待它收到服务器端响应。— 百度百科

HTTP是无状态协议,意味着服务器不会在两个请求之间保留任何数据(状态)。在同一个连接中,两个执行成功的请求之间是没有关系的。这就带来了一个问题,用户没有办法在同一个网站中进行连续的交互,比如在一个电商网站里,用户把某个商品加入到购物车,切换一个页面后再次添加了商品,这两次添加商品的请求之间没有关联,浏览器无法知道用户最终选择了哪些商品。而使用 HTTP 的头部扩展,HTTP Cookies就可以解决这个问题。把 Cookies 添加到头部中,创建一个会话让每次请求都能共享相同的上下文信息,达成相同的状态。通过上述得出结论,http特点是:无状态,无连接,简单快速。

HTTP 交互流程

一个连接是由传输层来控制的,这从根本上不属于 HTTP 的范围。HTTP并不需要其底层的传输层协议是面向连接的,只需要它是可靠的,或不丢失消息的(至少返回错误)。在互联网中,有两个最常用的传输层协议:TCP是可靠的,而 UDP 不是。因此,HTTP依赖于面向连接的 TCP 进行消息传递,但连接并不是必须的。

  • TCP:面向连接(如打电话要先拨号建立连接)
  • UDP:是无连接的,即发送数据之前不需要建立连接

关于 TCPUDP这里不做多余赘述,如果想要深入了解两者之间的优缺点以及区别的话,有时间再详细的介绍一下。

其实 HTTP 交互流程就是基于 TCP 连接进行消息传递的,然而这个连接可有可无,具体交互流程如下图:

结合上图详细说明经历的过程:

  1. 打开一个 TCP 连接:TCP 连接被用来发送一条或多条请求,以及接受响应消息。客户端可能打开一条新的连接,或重用一个已经存在的连接,或者也可能开几个新的 TCP 连接连向服务端
  2. 发送一个 HTTP 报文:HTTP 报文(在 HTTP/ 2 之前)是语义可读的。在 HTTP/ 2 中,这些简单的消息被封装在了帧中,这使得报文不能被直接读取,但是原理仍是相同的
  3. 读取服务端返回的报文信息, 服务器端接收到请求后,进行处理,然后将处理结果响应客户端(HTTP 协议)
  4. 关闭连接或者为后续请求重用连接,关闭客户端和服务器端的连接(HTTP1.1 后不会立即关闭)

HTTP 流水线启动时,后续请求都可以不用等待第一个请求的成功响应就被发送。然而 HTTP 流水线已被证明很难在现有的网络中实现,因为现有网络中有很多老旧的软件与现代版本的软件共存。因此,HTTP流水线已被在有多请求下表现得更稳健的 HTTP/2 的帧所取代。

HTTP 报文

Linux 系统下有一个 curl 指令可以通过这个命令来观测一下 HTTP 的请求过程。

curl -v https://segmentfault.com/

输入完之后回车就会看到下面这些信息:

图中 > 开始的是客服端发送给服务端的信息,以 < 开始的为服务端返回给客户端的一些信息。当客户端发起一个 Ajax 请求时,浏览器会携带一些信息发送给服务端,HTTP请求头提供了关于请求,响应或者其他的发送实体的信息。请求报文分为以下几个部分:

  1. General(请求行)
  2. Response Headers(请求头)
  3. Request Headers(响应头)

这三个部分分别承载了服务端以及客户端所需要的信息,在浏览器中种 NetWork 中可以查看到其信息内容,接下来就一一介绍一下:

General

这部分主要提供的是一些公用的请求头信息:

Request URL: https://segmentfault.com/search?q=search
Request Method: GET
Status Code: 200 
Remote Address: 112.126.83.219:443
Referrer Policy: no-referrer-when-downgrade
  • Request URL:请求地址
  • Request Method:请求方式
  • Status Code:状态码
  • Remote Address:请求的远程地址
  • Referrer Policy: 过滤 Referrer 报头内容

上述信息表明,客户端向服务器发送一个 http 请求,其请求地址为 https://segmentfault.com/search?q=search,使用GET 方式发起这个请求,请求返回状态为200,连接的远程地址为112.126.83.219:443,过滤报头采用的是不传递Referrer

向前面几个应该都比较熟悉也通俗易懂,当看到的这的时候心里有一些些的小疑惑 Remote Address 是什么?Referrer Policy过滤报头的规则有哪些?

Remote Address

关于 Remote Address 远程连接地址,Remote Address代表客户端的 IP,但它的值不是由客户端提供的,而是服务端根据客户端的IP 指定的,当你的浏览器访问某个网站时,假设中间没有任何代理,那么网站的 web 服务器(Nginx,Apache等)就会把 Remote Address 设为你的机器 IP,如果你用了某个代理,那么你的浏览器会先访问这个代理,然后再由这个代理转发到网站,这样 web 服务器就会把 Remote Address 设为这台代理机器的 IP。以至于后面的443 端口,也简单的看了一下,443端口即网页浏览端口,主要是用于 HTTPS 服务,是提供加密和通过安全端口传输的另一种 HTTP。在一些对安全性要求较高的网站,比如银行、证券、购物等,都采用HTTPS 服务,这样在这些网站上的交换信息,其他人抓包获取到的是加密数据,保证了交易的安全性。我也没有做深入的了解,大概就是这个样子吧。

Referrer Policy

Referrer-Policy的作用就是为了控制请求头中 referrer 的内容,目前是一个候选标准,不过已经有部分浏览器支持该标准。目前 Referrer-Policy 只包含以下几种值:

解释
no-referrer 不显示 referrer 的任何信息在请求头中。
no-referrer-when-downgrade 这是默认值。当从 https 网站跳转到 http 网站或者请求其资源时(安全降级 HTTPS→HTTP),不显示 referrer 的信息,其他情况(安全同级 HTTPS→HTTPS,或者 HTTP→HTTP)则在 referrer 中显示完整的源网站的 URL 信息。
same-origin 表示浏览器只会显示 referrer 信息给同源网站,并且是完整的 URL 信息。所谓同源网站,是协议、域名、端口都相同的网站。
origin 表示浏览器在 referrer 字段中只显示源网站的源地址(即协议、域名、端口),而不包括完整的路径。
strict-origin 该策略更为安全些,和 origin 策略相似,只是不允许 referrer 信息显示在从 https 网站到 http 网站的请求中(安全降级)。
origin-when-cross-origin 当发请求给同源网站时,浏览器会在 referrer 中显示完整的 URL 信息,发个非同源网站时,则只显示源地址(协议、域名、端口)
strict-origin-when-cross-origin 和 origin-when-cross-origin 相似,只是不允许 referrer 信息显示在从 https 网站到 http 网站的请求中(安全降级)。
unsaft-url 浏览器总是会将完整的 URL 信息显示在 referrer 字段中,无论请求发给任何网站。

Referrer-Policy值不是固定不变的,而是可是通过程序手动设置,一般都会不会去手动更改除非网页中不存在一些敏感信息,那就默认使用no-referrer-when-downgrade。这里就多说了,如果有兴趣的可以调研一下。

Response Headers

这部分存储的是响应头信息,当服务端接受到请求,并处理完成之后需要向客户端做出应答。

cache-control: no-store, no-cache, must-revalidate
content-encoding: gzip
content-type: text/html; charset=UTF-8
date: Fri, 28 Jun 2019 09:32:09 GMT
expires: Thu, 19 Nov 1981 08:52:00 GMT
pragma: no-cache
status: 200
strict-transport-security: max-age=15768000; preload
x-hit: web1
  • cache-control:响应输出到客户端后,服务端通过该报文头告诉客户端如何控制响应内容的缓存
  • content-encoding:文档编码(Encode)方法。只有在解码之后才可以得到 Content-Type 头指定的内容类型
  • content-type:文档类型
  • date:当前的 GMT 时间,可以用 setDateHeader 来设置
  • expires:文档过期时间,文档到期后则不再缓存
  • pragma:设置消息头,(no-cache)强制清除缓存
  • status:服务器响应状态码
  • strict-transport-security:安全功能,它告诉浏览器只能通过 HTTPS 访问当前资源,而不是 HTTP
Request Headers

这部分承载的是请求头的信息,当客户端向服务端发送请求时,需要传递给服务端的信息内容。

:authority: segmentfault.com
:method: GET
:path: /search?q=1
:scheme: https
accept: text/html,application/xhtml+xml,application/xml;
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9
cookie: e23800c454aa573c0ccb16b52665ac26=1561712973
referer: https://segmentfault.com/
user-agent: Chrome/75.0.3770.100 Safari/537.
  • :authority:请求权限(HTTP2.0)
  • :method:请求方式(HTTP2.0)
  • :path:请求地址(HTTP2.0)
  • :scheme:请求协议(HTTP2.0)
  • accept:指定客户端可以接受的内容类型,比如文本,图片,应用等等,内容的先后排序表示客户端接收的先后次序,每种类型之间用逗号隔开。
  • accept-encoding:客户端接收编码类型,一些网络压缩格式:Accept-Encoding: gzip, deflate, sdch。相对来说,deflate 是一种过时的压缩格式,现在常用的是 gzip
  • accept-language:客户端可以接受的语⾔言类型,参数值规范和 accept 的很像。一般就接收中文和英文,有其他语言需求自行添加。
  • cookie:同样是一个比较关键的字段,Cookie 是 client 请求服务器时,服务器会返回一个键值对样的数据给浏览器,下一次浏览器再访问这个域名下的网页时,就需要携带这些键值对数据在 Cookie 中,用来跟踪浏览器用户的访问前后路径。
  • referer:浏览器上次访问的网页 url,uri。由于 http 协议的无记忆性,服务器可从这里了解到客户端访问的前后路径,并做一些判断,如果⼀一次访问的 url 不能从前一次访问的页面上跳转获得,在一定程度上说明了请求头有可能伪造。
  • user-agent:中文名用户代理,服务器从此处知道客户端的操作系统类型和版本,电脑 CPU 类型,浏览器 种类版本,浏览器渲染引擎,等等。

accept-language共分为下列几种:

zh-CN:中文简体大陆
zh:其他中文
en-US:英语美语
en:其他英语

Cookie就是存储在客户端的一小段文本,因为 cookie 是存储在客户端浏览器中的,Cookie不能作为代码执行,也不会传送病毒,且为你所专有,并只能由提供它的服务器来读取。保存的信息片断以 名 / 值 对(name-value)的形式储存,一个 名 / 值 对仅仅是一条命名的数据。一个网站只能取得它放在你的电脑中的信息,它无法从其它的 cookie 文件中取得信息,也无法得到你的电脑上的其它任何东西。

const express = require('express');
const cookieParser = require('cookie-parser');
var app = express();
app.use(cookieParser('sign'));
app.get('/set', function(req, res) {res.cookie('name', 'TracyYu', {maxAge: 9999999, httpOnly: true, signed: true});
    res.send('cookie 设置成功');
})
app.get('/get', function(req, res) {console.log(req.signedCookies);
    res.send('success')
})
app.listen('3000', function() {console.log('3000 成功');
})

通过上面代码中对 cookie 进行设置之后,用户访问 /set 路由的是时候已经把 cookie 设置到了浏览器的头部,当用户访问 /get 路由的时候,由于在浏览器中已经设置好 cookie,在同属于一个服务的情况下是可以直接获取到cookie 的。当然除了上述所说,通过 document 也是可以手动设置 cookie 的,在客户端设置的 cookie 在服务端同样是也可以获取到的。

document.cookie="userId=929";

这样就将名为 userIdcookie值设置为了 929,现在访问/get 同样就能拿到在客户端设置的 cookie 值了。

请求方式

http中经常用的到的就是 getpost两种,在开发过程中会遵循 RESTful 接口风格,这是一种现在比较流行的接口风格,使用这种接口风格需要用到一些其他的请求方式,http请求方式一共有 8 种。

请求方式 描述
OPTIONS 允许客户端查看服务器的性能,服务器针对特定资源所支持的 HTTP 请求方法,也可以利用向 web 服务器发送‘*’的请求来测试服务器的功能性
HEAD 向服务器索与 GET 请求相一致的响应,只不过响应体将不会被返回。这一方法可以再不必传输整个响应内容的情况下,就可以获取包含在响应小消息头中的元信息。
GET 向特定的资源发出请求。它本质就是发送一个请求来取得服务器上的某一资源。资源通过一组 HTTP 头和呈现数据(如 HTML 文本,或者图片或者视频等)返回给客户端。GET 请求中,永远不会包含呈现数据。
POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST 请求可能会导致新的资源的建立和 / 或已有资源的修改。
PUT 向指定资源位置上传其最新内容
DELETE 请求服务器删除 Request-URL 所标识的资源
TRACE 回显服务器收到的请求,主要用于测试或诊断
CONNECT HTTP/1.1 协议中预留给能够将连接改为管道方式的代理服务器。

HTTP定义了与服务器交互的不同方法,最基本的方法是 GETPOST(开发关心的只有 GET 请求和 POST 请求)。

GET 和 POST 长度的限制问题

GET POST
GET 是通过 URL 提交数据,因此 GET 可提交的数据量就跟 URL 所能达到的最大长度有直接关系 HTTP 协议没有对 POST 进行任何限制,一般是受服务器配置限制或者内存大小
HTTP 协议对 URL 长度是没有限制的;限制 URL 长度大多数是浏览器或者服务器的配置参数 PHP 下可以修改 php.conf 的 postmaxsize 来设置 POST 的大小

其实这里有一个很大的误区,http协议并未规定 GETPOST的长度限制,GET的最大长度限制是因为浏览器和 web 服务器限制了 URL 的长度,不同的浏览器和 web 服务器,限制的最大长度不一样,要支持 IE,则最大长度为2083byte,若支持Chrome,则最大长度8182byte,首先即使GET 有长度限制,也是限制的整个 URL 的长度,而不仅仅是参数值数据长度。

GET 和 POST 的安全性

  1. GET 是通过 URL 方式请求,可以直接看到,明文传输
  2. POST 是通过请求 header 请求,可以开发者工具或者抓包可以看到,同样也是明文的
  3. GET 请求会保存在浏览器历史纪录中,还可能会保存在 Web 的日志中

GET请求指定资源的表示形式。注意,GET不应该用于产生副作用的操作,比如在 web 应用程序中使用它执行操作。原因之一是 GET 可能被机器人或爬行器任意使用,它们不需要考虑请求应该引起的副作用。POST将要处理的数据 (例如,从HTML 表单)提交给标识的资源。数据包含在请求体中。这可能会导致创建新资源或更新现有资源,或者两者兼而有之。使用 HTTP 协议的服务不应该使用基于 GET 的表单来提交敏感数据,因为这会导致这些数据在 Request-URI 中编码。许多现有服务器,代理和用户代理会将请求 URI 记录在第三方可能看到的某个位置。服务器可以使用基于 POST 的表单提交。

GET 与 POST 请求过程

POST请求的过程:

  1. 浏览器请求 tcp 连接(第一次握手)
  2. 服务器答应进行 tcp 连接(第二次握手)
  3. 浏览器确认,并发送 post 请求头(第三次握手,这个报文比较小,所以 http 会在此时进行第一次数据发送)
  4. 服务器返回 100 Continue 响应
  5. 浏览器发送数据
  6. 服务器返回 200 OK 响应

GET请求的过程:

  1. 浏览器请求 tcp 连接(第一次握手)
  2. 服务器答应进行 tcp 连接(第二次握手)
  3. 浏览器确认,并发送 get 请求头和数据(第三次握手,这个报文比较小,所以 http 会在此时进行第一次数据发送)
  4. 服务器返回 200OK 响应

总结

原本想说一写状态码相关的东西,但是简单的看了一下,好像又没有什么好说的,百度百科说的也很清楚,就不在文章里面赘述了。

简单的对 http 协议做了一些小的介绍与总结,如果文章中有哪些地方有问题,请在下方留言指正,我会尽快做出改正。

正文完
 0