http协议

前端 0 723 0
发表于: 2021-03-22 00:00:14

简介: 暂无~

http协议

超文本传输协议(HyperText Transfer Protocol)是一种无状态的,以请求/应答方式运行的协议

优点

  1. 「灵活可扩展」。一个是语法上只规定了基本格式,空格分隔单词,换行分隔字段等。另外一个就是传输形式上不仅可以传输文本,还可以传输图片,视频等任意数据。
  2. 「请求-应答模式」,通常而言,就是一方发送消息,另外一方要接受消息,或者是做出相应等。
  3. 「可靠传输」,HTTP是基于TCP/IP,因此把这一特性继承了下来。
  4. 「无状态」

缺点

  1. 「无状态」,有时候,需要保存信息,比如像购物系统,需要保留下顾客信息等等,另外一方面,有时候,无状态也会减少网络开销,比如类似直播行业这样子等,这个还是分场景来说。
  2. 「明文传输」,即协议里的报文(主要指的是头部)不使用二进制数据,而是文本形式。这让HTTP的报文信息暴露给了外界,给攻击者带来了便利。
  3. 「队头阻塞」,当http开启长连接时,共用一个TCP连接,当某个请求时间过长时,其他的请求只能处于阻塞状态,这就是队头阻塞问题。

http报文格式

请求报文

请求行

请求行由请求Method, URL 字段和HTTP Version三部分构成, 总的来说请求就是定义了本次请求的请求方式, 请求的地址, 以及所遵循的HTTP协议版本例如:

GET /example.html HTTP/1.1 (CRLF)

HTTP协议的方法有:

GET: 请求获取Request-URI所标识的资源

POST: 在Request-URI所标识的资源后增加新的数据

HEAD: 请求获取由Request-URI所标识的资源的响应消息报头

PUT: 请求服务器存储或修改一个资源,并用Request-URI作为其标识

DELETE: 请求服务器删除Request-URI所标识的资源

TRACE: 请求服务器回送收到的请求信息,主要用于测试或诊断

CONNEC: 保留将来使用

OPTIONS: 请求查询服务器的性能,或者查询与资源相关的选项和需求

请求头

消息报头由一系列的键值对组成,允许客户端向服务器端发送一些附加信息或者客户端自身的信息,主要包括:

  • Accept:用户代理可处理的媒体类型
  • Accept-charset:优先的字符集
  • Accept-Encoding:优先的编码格式
  • Accept-Lauguage:有限的语言(中文,英文等)
  • Authorization:Web认证信息(常用来携带token)
  • Host:请求资源所在的服务器(唯一一个必须的)
  • Range:实体请求的字节范围
  • User-Agent:HTTP客户端程序的信息
  • If-Match:比较实体标记(ETage)
  • If-None-Match:比较实体标记(ETage) 与lf-Match相反
  • lf-Modified-Since:比较资源更新时间(Last-Modified)
  • lf-Unmodified-Since:比较资源更新时间(Last-Modified),与lf-Modified-Since相反
  • If-Rnages:资源未更新时发送实体byte的范围请求

请求正文

只有在发送POST请求时才会有请求正文,GET方法并没有请求正文。

响应报文

HTTP响应也由三部分组成,包括状态行,消息报头,响应正文。

响应行

响应行也由三部分组成,包括HTTP协议的版本,状态码,以及对状态码的文本描述。例如:

HTTP/1.1 200 OK (CRLF)

状态码

1xx:指示信息–表示请求已接收,继续处理

2xx:成功–表示请求已被成功接收、理解、接受

3xx:重定向–要完成请求必须进行更进一步的操作

4xx:客户端错误–请求有语法错误或请求无法实现

5xx:服务器端错误–服务器未能实现合法的请求

  • 200 OK 表示从客户端发来的请求在服务器端被正确请求。

  • 204 No content,表示请求成功,但没有资源可返回。

  • 200 from memory cache 不访问服务器,直接读缓存,从内存中读取缓存。此时的数据时缓存到内存中的,当kill进程后,也就是浏览器关闭以后,数据将不存在。但是这种方式只能缓存派生资源

  • 200 from disk cache 不访问服务器,直接读缓存,从磁盘中读取缓存,当kill进程时,数据还是存在。这种方式也只能缓存派生资源

  • 301 moved permanently,永久性重定向,表示资源已被分配了新的 URL,这时应该按 Location 首部字段提示的 URI 重新保存。

  • 302 found,临时性重定向,表示资源临时被分配了新的 URL。

  • 304 Not Modified 访问服务器,发现数据没有更新,服务器返回此状态码。然后从缓存中读取数据。

  • 当 301、302、303 响应状态码返回时,几乎所有的浏览器都会把 POST 改成 GET,并删除请求报文内的主体,之后请求会自动再次发送 301、302 标准是禁止将 POST 方法改变成 GET 方法的,但实际使用时大家都会这么做400 bad request,请求报文存在语法错误。

  • 401 unauthorized,表示发送的请求需要有通过 HTTP 认证的认证信息。

  • 403 forbidden,表示对请求资源的访问被服务器拒绝。

  • 404 not found,表示在服务器上没有找到请求的资源。

  • 405 Method Not Allowed,服务器禁止使用该方法,客户端可以通过options方法来查看服务器允许的访问方法

  • 500 internal sever error,表示服务器端在执行请求时发生了错误。

  • 502 Bad Gateway,服务器自身是正常的,访问的时候出了问题,具体啥错误我们不知道。

如果没有设置http缓存,浏览器发送请求但是返回的数据和上次的一样,返回状态码:304 Not Modified;如果设置了http缓存,如果命中强缓存会返回200 OK (from disk cache,from memory cache等);如果命中协商缓存,会返回304 Not Modified

响应头

  • Accept-Range:是否接收范围请求
  • Age:推算资源创建时间
  • Server:HTTP服务器的安装信息
  • ETag:资源的匹配信息(相当于资源的id)
  • location:令客户端重定向的URL
  • Retry-After:对客户端再次发起请求的时机要求(主要配合503状态码使用)
  • Vary:代理服务器缓存的管理信息

响应报文

通用首部字段

请求报文和响应报文都会使用的首部字段。

  • cache-Control:控制缓存的行为
  • Connection:连接的管理(keep-alive)
  • Data:创建报文的日期
  • via:代理服务器的相关信息
  • pragma:报文指令
  • Trailer:报文末端首部
  • Upgrade:升级为其他协议
  • Transfer-Encoding:报文主体的编码方式

实体首部字段

实体首部字段是包含在请求报文和响应报文中的实体部分所使用的首部。

  • Allow,告诉客户端,服务器能接受的http请求方法,比如GET、POST、DELETE、OPTIONS、PUT等,当客户端使用的方法,服务器不能够支持的时候就会响应405 Method Not Allowed
  • Content-Encoding:实体主体的编码方式
  • Content-Charset:实体主体的字符集
  • Content-Language:实体主体的语言
  • Cntent-Length:实体主体的大小(字节长度)
  • Content-Type:实体主体的媒体类型
  • Content-Range:实体主体的位置范围
  • Expires:实体主体的过期时间(配合cache-control来使用,控制缓存)
  • Last-Modify:实体主体的最后修改时间

HTTP 缓存机制

http缓存机制主要在http响应头中设定,响应头中相关字段为Expires、Cache-Control、Last-Modified、If-Modified-Since、Etag。

强缓存

不会向服务器发送请求,直接从缓存中读取资源,在chrome控制台的Network选项中可以看到该请求返回200的状态码,并且size显示from disk cache或from memory cache两种(灰色表示缓存)。

  • **Expires :**response header里的过期时间,浏览器再次加载资源时,如果在这个过期时间内,则命中强缓存。
  • **Cache-Control:**当值设为max-age=300时,则代表在这个请求正确返回时间(浏览器也会记录下来)的5分钟内再次加载资源,就会命中强缓存。

区别:Expires 是http1.0的产物,Cache-Control是http1.1的产物
两者同时存在的话,Cache-Control优先级高于Expires
Expires其实是过时的产物,现阶段它的存在只是一种兼容性的写法

app.use('/star', function (req, res,) {
    res.setHeader('Cache-Control', 'max-age=3')
    var data = { code: new Date().getTime() }
    res.json(data)
})

设置了/star接口为强缓存,第一次请求star,返回200,然后在3秒内不管请求多少次star,都是从缓存里面读数据,如果三秒后请求,服务器收到请求后判断,获取到的数据和上一次获取的数据对比没有更新(即请求头If-None-Match和返回的响应头etag一致),就会返回304状态码和新的response header通知浏览器从缓存中读取资源;如果对比后发现数据更新了,就会返回200状态码并且从请求响应里读取数据

协商缓存

协商缓存使用Cache-Control的no-cache和no-store实现

向服务器发送请求,服务器接收到这个请求,会根据这个请求的request header的一些参数如:If-None-Match,来判断是否命中协商缓存,如果服务器接收到这个请求的请求头有If-None-Match,就会判断这个If-None-Match是否和这次请求返回的Etag一致,如果一致就代表命中协商缓存,就会返回304状态码和带上新的response header通知浏览器从缓存中读取资源

app.use('/tag', function (req, res,) {
    /**
     * 协商缓存,每次都会发请求判断资源是否更新,
     * 如果资源更新了,就返回200状态码,如果没更新就返回304状态码
    */
    // 设置协商缓存
    res.setHeader('Cache-Control', 'no-cache')
    // 获取请求头的if-none-match
    console.log(req.headers['if-none-match'])
    var data = { code: new Date().getFullYear() }
    res.json(data)
    // 设置了Cache-Control:no-cache后,手动设置status状态码不管用。
    // res.status(200).json(data)
})

上面是node设置了/tag接口的协商缓存,浏览器第一次请求/tag时,会在请求头if-none-match带上上次响应头的Etag(因为是第一次请求,因此获取到的if-none-match为undefined),node收到这个请求后,判断if-none-match,发现是undefined,即代表是第一次请求,因此就返回200状态码以及根据返回的data数据生成的唯一标识给响应头Etag;

浏览器第二次请求/tag时,会把上次请求的/tag时的响应头Etag,设置在请求头if-none-match上,node服务器收到请求后,判断请求头的if-none-match,发现这个if-none-match和这次返回的data生成的唯一标识一样(因为data都是{code:2021},因此生成的标识也一样),则命中协商缓存,返回304状态码和新的response header通知浏览器从缓存中读取资源。

app.use('/tag', function (req, res,) {
    /**
     * 协商缓存,每次都会发请求判断资源是否更新,
     * 如果资源更新了,就返回200状态码,如果没更新就返回304状态码
    */
    // 设置协商缓存
    res.setHeader('Cache-Control', 'no-cache')
    // 获取请求头的if-none-match
    console.log(req.headers['if-none-match'])
    var data = { code: new Date().getTime() }
    res.json(data)
    // 设置了Cache-Control:no-cache后,手动设置status状态码不管用。
    // res.status(200).json(data)
})