在B站看猫片被老板发现?不如按下F12学学HTTP 3

简介: 在B站看猫片被老板发现?不如按下F12学学HTTP

6. Headers

Content-Length

Content-Length是HTTP的消息长度, 用十进制数字表示。Content-Length首部指出报文中消息的当前实际字节大小。如果消息文本进行了gzip压缩的话, Content-Length指的就是压缩后的大小而不是原始大小。

正常情况下Content-Length是不需要手动去设置的,大部分语言的网络库都会自动封装好,但是如果在一些特殊情况下,出现Content-Length与实际要发送的消息大小不一致,就会出现一些问题。

  • 如果Content-Length < 实际长度
    下面启动一个HTTP服务器,所有语言都一样,示例里使用了golang。
package main
import (
  "fmt"
  "io/ioutil"
  "log"
  "net/http"
)
// w表示response对象,返回给客户端的内容都在对象里处理
// r表示客户端请求对象,包含了请求头,请求参数等等
func index(w http.ResponseWriter, r *http.Request) {
  b, _ := ioutil.ReadAll(r.Body)
  fmt.Printf("request body=%#v, content_length=%v \nheaders=%v",string(b), r.ContentLength, r.Header)
  // 往w里写入内容,就会在浏览器里输出
  fmt.Fprintf(w, string(b))
}
func main() {
  // 设置路由,如果访问/,则调用index方法
  http.HandleFunc("/", index)
  // 启动web服务,监听9090端口
  err := http.ListenAndServe(":9999", nil)
  if err != nil {
      log.Fatal("ListenAndServe: ", err)
  }
}
  • 在控制台输入
<span class="katex-html" aria-hidden="true" style="font-size: inherit;color: inherit;line-height: inherit;overflow-wrap: inherit !important;word-break: inherit !important;"> curl -L -X POST 'http://127.0.0.1:9999' -H 'Content-Type: application/json' -H 'Content-Length: 5' -d '1234567' |  jq
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                               Dload  Upload   Total   Spent    Left  Speed
100    12  100     5  100     7    828   1160 --:--:-- --:--:-- --:--:--  1400
12345
</span class="katex-html" aria-hidden="true">
  • 输入的body是 1234567,共7个数字,但是输入的 Content-Length为 5。到了服务器那,收到了 12345,共5个数字,数量上跟输入的Content-Length一致。由此可见当Content-Length < 实际长度, 消息会被截断。
  • 如果Content-Length >  实际长度
    还是上面的服务端代码,但是控制台输入以下命令
$ curl -L -X POST 'http://127.0.0.1:9999' -H 'Content-Type: application/json' -H 'Content-Length: 100' -d '1234567' | jq
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                               Dload  Upload   Total   Spent    Left  Speed
100     7    0     0    0     7      0      0 --:--:--  0:01:19 --:--:--     0
  • 这次情况不太一样,会发现请求一直阻塞没有返回。这是因为输入的body是 1234567,共7个数字,但是输入的 Content-Length为 100。也就是服务端一直认为这次的body长度为100,但是目前只收到了部分消息(长度为7),剩余的长度为93的消息由于各种原因还在路上,因此选择傻傻等待剩下的消息,就造成了上面提到的阻塞。

Range

视频播放需要支持用户调整播放进度,支持让用户选择直接跳到中间部分开始播放。为了实现这个功能,需要通过HTTP Range Requests 协议用于指定需要获取视频片段。而 Request Header里的range头则是用于指定要请求文件的起始和结束位置。

  • 如果服务器不支持,直接忽略 Range 头,浏览器会正常按流式加载整个视频文件,以状态码 200 响应即可。另外,当我们在 html 中放一个 video 标签,浏览器会直接发起一个 Range: bytes=0- 的请求,向服务器请求从开始到结尾的完整文件。
  • 如果服务器支持 Range Requests,会读取视频文件,并将他的第 162653~242638 字节提取出来,响应码为 206,则浏览器会在接收到足够字节(比如当前播放进度往后推20s)时结束掉请求,以节省网络流量;当播放进度继续往前,缓存不够时,浏览器会发起一个新的 Range Requests 请求,请求的 Range 直接从缓存结尾的字节开始,只加载剩余的部分文件。同时返回的Response Headers中有一个 content-range 的字段域,用于告诉了客户端发送了多少数据。content-range  描述了响应覆盖的范围和整个实体长度。一般格式:Content-Range:开始字节位置-结束字节位置/文件大小(byte)

Connection

长连接和短连接

  • Connection: close
    表示请求响应完成之后立即关闭连接,这是HTTP/1.0请求的默认值。每次请求都经过“创建tcp连接 -> 请求资源 -> 响应资源 -> 释放连接”这样的过程
  • Connection: keep-alive
    表示连接不立即关闭,可以继续响应下一个请求。HTTP/1.1的请求默认使用一个持久连接。可以做到只建立一次连接,多次资源请求都复用该连接,完成后关闭。流程上是 建立tcp连接 -> 请求资源 -> 响应资源 -> … (保持连接)…  ->  第n次请求资源 -> 第n次响应资源 -> 释放连接。

在http1.1中Request Header和Reponse Header中都有可能出现一个Connection: keep-alive 头信息。Request Header里的Connection: keep-alive 头是为了告诉服务端,客户端想要以长连接形式进行通信。而Response Header里的Connection: keep-alive 头是服务端告诉客户端,我的服务器支持以长连接的方式进行通信。如果不能使用长连接,会返回  Connection: close ,相当于告诉客户端“我不支持长连接,你死了这条心,老老实实用短连接吧” 。

HTTP为什么要使用长连接

我们知道 HTTP 建立在 TCP 传输层协议之上,而 TCP 的建立需要三次握手,关闭需要四次挥手,这些步骤都需要时间,带给 HTTP 的就是请求响应时延。如果使用短连接,那么每次数据传输都需要经历一次上面提到的几个步骤,如果能只连接一次,保持住这个连接不断开,期间通信就可以省下建立连接和断开连接的过程,对于提升HTTP性能有很大的帮助。

  • 可以看到,在使用 Connection: close 通信时,每次都需要重新经历一次握手挥手。可以通过 Connection: keep-alive 省下这部分的资源消耗。

  • 长连接可以省去较多的TCP建立和关闭的操作,减少浪费,节约时间。对于频繁请求资源的客户来说,较适用长连接。但是在长连接的应用场景下,需要有一方主动关闭连接。如果客户端和服务端之间的连接一直不关闭的话,连接数则会越来越多,严重的时候会造成资源占用过高。
  • 解决方案也比较简单。如果这些连接其实长时间内并没有任何数据传输的话,那其实属于空闲连接,这时候可以在服务端设置空闲连接的存活时间,超过一定时间后由服务端主动断掉,从而保证无用连接及时释放。

Cookies

Cookies是什么

  1. Cookie 是浏览器访问服务器后,服务器传给浏览器的一段数据。里面一般带有该浏览器的身份信息。
  2. 浏览器需要保存这段数据,不得轻易删除。
  3. 此后每次浏览器访问该服务器,都必须带上这段数据。服务器用使用这段数据确认浏览器身份信息。

Cookie的作用

Cookie 一般有两个作用。

1.识别用户身份。

  • 举个例子。用户 A 用浏览器访问了“猫猫网”,“猫猫网”的服务器就会立刻给 A 返回一段Cookie数据,内含「uid=a」。
  • 当 A 再次访问“猫猫网”下的其他页面时,比如跳转到“猫猫交友评论”,就会附带上「uid=a」这段数据。
  • 同理,用户 B 用浏览器访问“猫猫网” 时,就给 B 分配了一段Cookie数据,内含「uid=b」。B 之后访问“猫猫网”的时候,就会一直带上「uid=b」这段数据。
  • 因此“猫猫网”的服务器通过Cookie数据就能区分 A 和 B 两个用户了。

2.持久化用户信息。

  • 因为cookies的数据会被用户浏览器保存到本地下。因此可以利用这一特点保持一些简单的用户数据。
  • 比如一些博客网站,可以通过cookies记录下用户的性别年龄等信息,以此进行一些个性化展示。
  • 当然上面提到的都是一些比较粗糙的场景,是为了方便大家理解cookies的功能。实际使用cookies会非常谨慎。

Referrer Policy 和 Referrer

Referrer是什么

Referrer 是HTTP请求header的报文头,用于指明当前流量的来源参考页面,常被用于分析用户来源等信息。通过这个信息,我们可以知道访客是怎么来到当前页面的。比如在上面的请求截图里,可以看出我是使用https://www.bilibili.com/访问的视频资源。

Referrer Policy 是什么

  • Referrer 字段,会用来指定该请求是从哪个页面跳转页来的,里面的信息是浏览器填的。
  • 而 Referrer Policy 则是用于控制Referrer信息传不传、传哪些信息、在什么时候传的策略。

为什么要这么麻烦呢?因为有些网站一些用户敏感信息,比如 sessionid 或是 token 放在地址栏里,如果当做Referrer字段全部传递的话,那第三方网站就会拿到这些信息,会有一定的安全隐患。所以就有了 Referrer Policy,用于过滤 Referrer 报头内容。

比如在上面的请求截图里,可以看出我是使用strict-origin-when-cross-origin策略,含义是跨域时将当前页面URL过滤掉参数及路径部分,仅将协议、域名和端口(如果有的话)当作 Referrer。否则 Referrer 还是传递当前页的全路径。同时当发生降级(比如从 https:// 跳转到 http:// )时,不传递 Referrer 报头。

Cache-control

什么是cache-control

cache-control,用于控制浏览器缓存。简而言之,当某人访问网站时,其浏览器将在本地保存某些资源,例如图像和网站数据。当该用户重新访问同一网站时,缓存控制设置的规则会确定该用户是否从本地缓存中加载这些资源,或者浏览器是否必须向服务器发送新资源的请求。

什么是浏览器缓存

浏览器缓存是指浏览器本地保存网站资源,以便不必再次通过网络从服务器获取它们。例如,“猫猫网”的背景图像可以保存到本地缓存中,这样在用户第二次访问该页面时,该图像将从用户的本地文件加载,剩下网络获取资源的时间,页面加载速度就会更快。

但是浏览器也不会永远把这些网站资源放在本地,否则本地磁盘就会炸,所以会限定保存资源的时间,这叫生存时间(TTL)。如果 TTL 过期后用户请求缓存的资源,浏览器必须再次通过网络与服务器建立连接并重新下载这个资源。

常见的缓存控制策略

  • cache-control: private
    具有“private”指令的响应只能由客户端缓存,不能由中间代理(例如 CDN或代理)缓存。这些资源通常是包含私密数据的资源,例如显示用户个人信息的网站。
  • cache-control: public
    相反,“public”指令表示资源可以由任何缓存存储。
  • cache-control: no-store
    带有“no-store”指令的响应无法缓存到任何位置,也永不缓存。也就是说,用户每次请求此数据时,都必须将请求发送到源站服务器以获取新副本。此指令通常保留给包含极其敏感数据的资源,例如银行帐户信息。
  • cache-control: max-age
    此指令指定了生存时间,也就是资源在下载后可以缓存多少秒钟。例如,如果将最大期限设置为 1800,则首次从服务器请求资源后的 1800 秒(30 分钟)内,后续请求都会向用户提供该资源的缓存版本。如果 30 分钟后用户再次请求资源,则客户端需要向服务器重新请求该资源。
  • cache-control: no-cache
    从B站截图里可以看出,使用的缓存控制指令是cache-control: no-cache。它表示,只有先检查资源没有更新版本后,才可使用所请求资源的缓存版本。那么问题来了,怎么判断资源是否有更新版本呢?这就需要 ETag

ETag

Etag是 Entity tag的缩写,是服务端的一个资源版本的令牌标识。在 HTTP 响应头中将其传送到客户端。每当资源更新时,此令牌会更新。

比如,浏览器第一次请求资源的时候,服务端返回了这个资源的ETag: "095933fff2323351d3b495f2f879616f1762f752"

当浏览器再次请求这个资源的时候,浏览器会将If-None-Match: "095933fff2323351d3b495f2f879616f1762f752" 传输给服务端,服务端拿到该ETAG,对比资源是否发生变化。

  • 如果资源未发生改变,则返回304HTTP状态码,不返回具体的资源。
  • 否则表示资源已经更新,浏览器需要下载新版本以提供给用户。

此过程可确保用户始终获得资源的最新版本,并且无需进行不必要的下载。

最后

果然B站是个充满学习氛围的地方,看个猫片都能学到这么多硬核知识。接下来我打算去舞蹈区看看有没有适合你们的知识点。

我是小白,有空?一起在知识的海洋里呛水啊,懂我意思?

目录
相关文章
|
网络协议 前端开发 iOS开发
在B站看猫片被老板发现?不如按下F12学学HTTP 1
在B站看猫片被老板发现?不如按下F12学学HTTP
173 0
|
缓存 安全 应用服务中间件
在B站看猫片被老板发现?不如按下F12学学HTTP 2
在B站看猫片被老板发现?不如按下F12学学HTTP
123 0
|
Web App开发 监控 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
负载均衡: LVS(Layer 4), HAProxy(Layer 4、 7),Nginx(Layer 7) 虚拟化: LXC、KVM、Xen HA:Keepalived、Heartbeat 分布式缓存...
769 0
|
Web App开发 前端开发 算法
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
基于大数据的精准营销与应用场景 2015年08月11日 大数据 大数据营销时代来临营销学领域过去半个多世纪的发展让我们见证了从“以产品为中心”到“以客户为中心”的转变。
924 0
|
Web App开发 前端开发 Linux
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
问题症状 修改 linux 内核文件 #vi /etc/sysctl.conf后执行sysctl  -P 报错 error: "net.
562 0
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
概述 HDFS中的集中化缓存管理是一个明确的缓存机制,它允许用户指定要缓存的HDFS路径。NameNode会和保存着所需快数据的所有DataNode通信,并指导他们把块数据缓存在off-heap缓存中。
716 0
|
Web App开发 前端开发 Java
|
Web App开发 前端开发 Java
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
Runnable:一般指该线程正在执行状态中,该线程占用了资源,正在处理某个请求,例如有可能在对某个文件操作,有可能进行数据类型等转换。
608 0
|
Web App开发 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
1.修改dfs.datanode.max.transfer.threads = 4096 (如果运行hbase的话建议为16384),指定用于在DataNode间传输block数据的最大线程数,老版本的对应参数为dfs.
791 0
|
Web App开发 前端开发
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html><head><meta http-equiv="Cont
为什么要对数据进行归一化?     归一化后加快了梯度下降求最优解的速度;2)归一化有可能提高精度。下面我简单扩展解释下这两点。
773 0