HTTP —— HTTP 协议中的细节(超详细!!)

JavaEE传送门

JavaEE

【前端】JavaScript —— JS的基本语法之数组, 函数…

【前端】JavaScript —— WebAPI


目录

  • HTTP 协议
    • 抓包工具 fiddler
    • 协议格式
      • Request
      • Response
    • HTTP 协议中的细节
      • 认识 URL
        • URL 基本格式
        • URL encode/ decode
      • 认识 "方法" method
        • GET
        • POST
        • GET 和 POST 的区别
        • 其他方法
      • 认识请求 "报头" header
        • Host
        • Content-Length/ Content-Type
        • User-Agent (UA)
        • Referer
        • Cookie
      • 认识请求 "正文" body


HTTP 协议

应用层最广泛使用的协议只有 (主要是学习报文格式)

抓包工具 fiddler

借助抓包工具, 来分析 HTTP 协议, 本文使用的抓包工具是 fiddler (还有其他的一些, wieshark, Charles, chrome 等开发者工具)

推荐下载 classic 版本

HTTP —— HTTP 协议中的细节(超详细!!)_第1张图片

我们双击打开 fiddler

  • 左侧区域是抓到请求的列表 (我们的电脑上, 每时每刻都有应用程序, 通过 http 传输数据, 都能被 fiddler 抓到)

HTTP —— HTTP 协议中的细节(超详细!!)_第2张图片

  • 当我们双击左侧某个想关注的请求, 就会在右侧窗口显示出请求的具体情况

HTTP —— HTTP 协议中的细节(超详细!!)_第3张图片

在响应数据中

HTTP —— HTTP 协议中的细节(超详细!!)_第4张图片

# 注意事项 # 有的人可能抓不到想要抓的请求

  1. 需要开启 fiddler 抓取 HTTPS 的功能 (现在互联网上纯 HTTP 很少了, 更多的是 HTTPS . HTTPS 可以理解成升级版本的 HTTP, 在 HTTP 的基础上, 加了个加密层)

    HTTP —— HTTP 协议中的细节(超详细!!)_第5张图片

    首次勾选的时候, 点击 ok 后, 就会提示一个, 是否需要安装 “根证书”, 务必要点击 “是”

  2. 如果开启了上述 HTTPS 也安装了根证书, 还是抓不到. 检查是否你的电脑上安装了其他代理程序/ 代理作用的浏览器插件

    • 一些游戏加速器/ steam++… 本质上都是代理
    • 这些程序都会和 fiddler 打架, 可以同时装, 但是不能同时运行

协议格式

HTTP —— HTTP 协议中的细节(超详细!!)_第6张图片

下面我们来结合 fiddler 了解一下协议格式, 我们点击 “View Notepad” 用记事本查看.

HTTP —— HTTP 协议中的细节(超详细!!)_第7张图片


Request

我们先来查看 HTTP 请求, HTTP 是一个文本格式的协议 (构造一个 HTTP 请求, 本质上就是往一个 TCP socket 中, 按照下列格式写入数据即可)

HTTP —— HTTP 协议中的细节(超详细!!)_第8张图片

  1. 首行 (方法 URL 版本号)

    HTTP —— HTTP 协议中的细节(超详细!!)_第9张图片

  2. 请求头 header

    HTTP —— HTTP 协议中的细节(超详细!!)_第10张图片

  3. 空行 (一个 HTTP 请求的 header 可以有若干个, 就使用空行. 作为 header 的结束标志, 类似于 链表的 null)

  4. 正文 body (有的请求有, 有的请求没有)


Response

HTTP —— HTTP 协议中的细节(超详细!!)_第11张图片

  1. 首行 (版本号 状态码 状态码描述)

    HTTP —— HTTP 协议中的细节(超详细!!)_第12张图片

  2. 响应报头 header

    HTTP —— HTTP 协议中的细节(超详细!!)_第13张图片

  3. 空行

  4. 正文 body (正文可以是 json 数据, 也可以是 html, 也可以是 css, 也可以是 js, 也可以是图片…)

    HTTP —— HTTP 协议中的细节(超详细!!)_第14张图片


HTTP 协议中的细节

认识 URL

URL 基本格式

  • URL 唯一资源定位符 (用这个来找到网络上的资源)
  • URI 唯一资源标识符 (用这个来区分一个网络上的资源)
  • 这个两个概念非常相似, 很多时候, 不会显式区分

URL 就是浏览器地址栏里的一串地址

HTTP —— HTTP 协议中的细节(超详细!!)_第15张图片

URL 里面是有 “RFC 标准文档” 来进行描述的

RFC 标准文档: 描述了很多网络中的协议标准, 包括 IP, TCP. UDP, HTTP…

  • 如果我们想查看某个协议中的具体的细节, 应该搜索对应的文档编号, 比如URL 的详细规则由 因特网标准 RFC1738 进行了约定.
  • 我们可以通过搜索 xx RFC 来得知 xx 相对应的文档编号

# 注意 # URL 并非是 HTTP 独有的, 是给很多协议都能使用的.

下面我们来通过下面这串地址来更好的了解 URL

![](https://img-blog.csdnimg.cn/33a6afa518de4712abc4afb3de3a07ac.png =600x

HTTP —— HTTP 协议中的细节(超详细!!)_第16张图片

URL 需要定义到具体的资源, 这里就通过我们后面的带层次的文件路径来进行确定

HTTP —— HTTP 协议中的细节(超详细!!)_第17张图片

下面我们来举两个例子, 来更好的了解带层次的文件路径

# 真实存在的文件 (访问静态资源)

HTTP —— HTTP 协议中的细节(超详细!!)_第18张图片

# 虚拟出来的文件 (访问动态资源)

比如:

可以在 HTTP 服务器中, 加入一个特殊的逻辑, 比如请求的 URL 中的路径是 /test.

就直接在 HTTP 服务器中, 直接在内存中构造出一个 HTML, 返回到浏览器这边 (此时, 没有访问硬盘的真是文件, 而是直接在内存中拼了个 HTML 出来)

小知识: 在浏览器的 URL 里面端口号经常会省略不写, 省略的时候用的是当前协议的默认端口

  • https, 默认端口是 443

  • http, 默认端口是 80

HTTP —— HTTP 协议中的细节(超详细!!)_第19张图片

我们来举一个例子:

HTTP —— HTTP 协议中的细节(超详细!!)_第20张图片

此处的查询字符串, 是通过 “键值对” 格式来组织的

  • 键值对之间使用 & (按位与运算) 分割

  • 键和值之间, 使用 = 来分割

  • # 注意 # HTTP header 也是有很多键值对, 这里的键和值大多都是标准规定好的(虽然也可以有自定义的, 但是以标准的为主)

    而 URL 里面的 查询字符串, 键值对, 完全是自定义的

HTTP —— HTTP 协议中的细节(超详细!!)_第21张图片

比如: 每一个标题都是一个具体的片段 (同一个页面网址不断变化)

HTTP —— HTTP 协议中的细节(超详细!!)_第22张图片


URL encode/ decode

URL 中已经包含一些特殊含义的符号, 比如: / ? @

万一 query string 的 value 中, 也包含了这些特殊符号会怎么样呢?

很有可能会有问题(浏览器可能会错误的识别 URL, 服务器也可能会错误的解析 URL)

非常类似于, 编程语言里的 变量名 不能是 “关键字”

URL encode

本质上就是把特殊符号进行转义了, 这里转移的范围不仅仅是这些特殊符号, 还有汉字…

比如: 如果此时我们在搜索框中搜索 “C++”

再比如: 我们搜索 “鸪鸠”

HTTP —— HTTP 协议中的细节(超详细!!)_第23张图片

转译的规则, 就是把待转译的字符串, 每个字符的十六进制表示, 每个字节前加上一个 %

我们现在使用一个 utf8编码转换器

HTTP —— HTTP 协议中的细节(超详细!!)_第24张图片

# 总结 #

  • 把原始的字符, 转成转义后的字符 => URL encode (编码)
  • 把转移后的字符还原成原始的字符 => URL decode (编码)

认识 “方法” method

HTTP 中非常重要的部分, 可以把 方法理解成, 这个请求想做什么

方法 说明 支持的HTTP协议版本
GET 获取资源 1.0, 1.1
POST 传输实体主体 1.0, 1.1
PUT 传输文件 1.0, 1.1
HEAD 获得报文首部 1.0, 1.1
DELETE 删除文件 1.0, 1.1
OPTIONS 询问支持的方法 1.1
TRACE 追踪路径 1.1
CONNECT 要求用隧道协议链接代理 1.1
LINK 建立和资源之间的联系 1.0
UNLINE 断开连接关系 1.0

方法的种类繁多, 但是使用最频繁的为 GET 和 POST


GET

最常用的 HTTP 请求方法

  1. 浏览器地址直接输入 URL, 此时就会触发 GET

  2. html 里面的 link, a, img, script 也会触发 GET 请求

    • href/ src 都会引用一个外部的资源, 本质上就是浏览器会重新发送一个 GET 请求, 来从服务器拿到对应的数据
    • 一个浏览器加载出一个页面, 往往要经过多重 HTTP 请求的交互

    比如:

    HTTP —— HTTP 协议中的细节(超详细!!)_第25张图片

    我们使用 fiddle 来看一下, 我们当前请求说蓝色字体的请求, 下面还有很多域名是 csdn 的请求, 都是当前页面 又给 csdn 服务器发送的其他的 http请求.

    我们按住 ctrl 再刷新, 我们能看到更多的请求

    HTTP —— HTTP 协议中的细节(超详细!!)_第26张图片

    • 浏览器在加载页面的时候. 往往要加载这个页面依赖的很多其他资源 css, 图片, js 等, 加载这些资源, 显然需要消耗不少时间的.
    • 为了提高页面加载效率, 浏览器就会对加载过的这些 css, 图片, js 进行缓存 (保存在你本地的磁盘上)
    • 下次再访问同一个网页, 之前的 css, 图片, js 就不必重新从网络加载, 而是直接读硬盘即可
    • 使用 ctrl + f5 强制刷新, 就可以让浏览器不走缓存, 直接强制重新从网络上获取资源
  3. form 表单 (html 里的 form 标签, 可以构造出 GET 请求)

  4. ajax

GET 请求的特点

  • 首行的第一部分为 GET
  • URL 的 query string 可以为空, 也可以不为空.
  • header 部分有若干个键值对结构.
  • body 部分为空.

如果需要给服务器传递一些参数, 这些参数通常就是通过 query string 来传过去

网上有这样的说法: GET 请求长度最多是 1KB/ 2KB/ 1MB…

⚠典型的错误说法

HTTP 协议由 RFC 2616 标准定义, 标准原文中明确说明: "Hypertext Transfer Protocol -- HTTP/1.1," does not specify any requirement for URL length. 没有对 URL 的长度有任何的限制.

标准虽然没有谈到长度上限, 但是浏览器和 HTTP 服务器在实现的时候, 可能是有长度上限的, 也可能是没有的 (取决于具体的实现)


POST

POST 应用场景 没有 GET 那么多

产生 POST 途径

  1. form
  2. ajax

POST 请求的特点

比如:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MfEDiaLs-1668752791805)(C:/Users/gu%27jiu/AppData/Roaming/Typora/typora-user-images/image-20221116195835044.png)]

  1. 方法叫做 POST
  2. URL 通常是没有 query string
  3. 也是有若干 header , 键值对的形式
  4. 通常有 body, body 的数据格式有很多种 (POST 在传递给服务器的时候, 通常会把信息放到 body 中)

GET 和 POST 的区别

  1. 先盖棺定论, GETPOST 没有本质区别 (使用 GET 实现的场景, 基本都可以使用 POST 代替; 使用 POST 实现的场景, 也可以用 GET 来代替)

  2. 再来谈细节上的区别

    • GET 的语义, 是 “从服务器获取个数据”, POST 的语义, 是 “往服务器上提交个数据” (HTTP 协议设计的 “初心”)

    • 使用习惯上, 给服务器传递的数据, GET 通常是放在 URL 的 query string 中, POST 通常是放在 body 中 (GET 也可以把数据放在 body 里, 但是很少见, 浏览器不一定能支持, 其他的 http 客户端是可以支持的; POST 也可以把数据放在 query string里, 但是很少见, 浏览器也是支持的)

    • GET 请求建议实现成 “幂等” 的, POST 一般则不要求实现成 “幂等”

      设计服务器的时候, 就需要提供一些 “接口/ API”

      • API 传入的参数, 就视为是输入

      • API 返回的结果, 就视为是输出

      幂等: 数学上的术语, 简单来说, 大概就是输入是确定, 输出结果也就是确定的

    • 在幂等的基础上, GET 的请求结果是可以被缓存的, POST 则一般不会缓存

      如果当前 GET 确实是幂等的, 就不必处理, 就让浏览器缓存, 没问题.

      如果当前 GET 不是幂等的, 就需要通过特殊技巧避免浏览器产生缓存 (典型的技巧就是让每次 GET 请求的 URL 都不相同, 通过特殊的 query string 来保证 URL 不同)

网上有这样的说法: POST 比 GET 更安全

依据是:

GET 是把参数放到 URL 中, 如果你实现登陆页面, 一点登录, 你的用户名和密码就直接以 query string 的形式放到 URL 里面了, 就直接显示到浏览器地址栏中了, 会被别人看到, 所以不安全.

POST 是把参数放到 body 中, body 不会显示到浏览器页面上, 多以就不会直接显示出来, 所以更安全

⚠典型的错误说法

虽然把用户名密码放到 URL 里确实不好, 但是放到 POST 的 body 中也没有更安全, 不能说 “不在界面上显示” 就是安全! !

只要你代码里没有进行加密, 此时就谈不上安全.


其他方法

  • PUT 与 POST 相似,只是具有幂等特性,一般用于更新
  • DELETE 删除服务器指定资源
  • OPTIONS 返回服务器所支持的请求方法
  • HEAD 类似于GET,只不过响应体不返回,只返回响应头
  • TRACE 回显服务器端收到的请求,测试的时候会用到这个
  • CONNECT 预留,暂无使用

认识请求 “报头” header

header 的整体的格式也是 “键值对” 结构, 每个键值对占一行. 键和值之间使用分号分割.

这里的键值对, 都是标准规定的, 有特定含义的, 当然这里也可以放一些自定义的键值对.

Host

Host 表示服务器主机的地址和端口

比如:

这里的端口可以省略, 省略则表示默认值

URL 中不是也有这个服务器主机的 IP 和端口, 为什么还需要一个 Host?

事实上, URL 中的 IP 和端口, 在 Host 里的 IP 和端口, 不一定完全一样.

当我们的请求是经过代理来访问的时候, 是可能会不一样的 (在 fiddler 中没有体现出来)

HTTP —— HTTP 协议中的细节(超详细!!)_第27张图片


Content-Length/ Content-Type

Content-Length: 表示 body 中的数据长度

Content-Type: 表示请求的 body 中的数据格式

  • 这两个字段不一定有, 但如果有一个, 就会有另一个

  • 如果请求没有body (GET) 就没有这两个字段

  • 如果请求有 body(POST) 就一定有这两个字段

Content-Length 不需要咱们手动来设置, 一般都是浏览器和 HTTP 服务器, 自己计算好的

Content-Type

body 中的数据可以放很多种格式, 存不同的格式, 对于接收方来说, 解析方式是截然不同的.

常见选项:

  • application/x-www-form-urlencoded: form 表单提交的数据格式. 此时 body 的格式形如:

    title=test&content=hello
    

    (这个格式和 query string 是一样的, 并且这里也是需要 URL encode 的)

  • multipart/form-data: form 表单提交的数据格式(在 form 标签中加enctyped=“multipart/form-data” . 通常用于提交图片/文件. body 格式形如:

    Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA 
    ------WebKitFormBoundaryrGKCBY7qhFd3TrwA 
    Content-Disposition: form-data; name="text" 
    title 
    ------WebKitFormBoundaryrGKCBY7qhFd3TrwA 
    Content-Disposition: form-data; name="file"; filename="chrome.png" 
    Content-Type: image/png 
    PNG ... content of chrome.png ... 
    ------WebKitFormBoundaryrGKCBY7qhFd3TrwA--
    
  • application/json: 数据为 json 格式. body 格式形如:

    {"username":"123456789","password":"xxxx","code":"jw7l","uuid":"d110a05ccde64b16a861fa2bddfdcd15"}
    

User-Agent (UA)

我们使用 fiddler 抓一下 我的主页. 其中有这样一行:
在这里插入图片描述

HTTP —— HTTP 协议中的细节(超详细!!)_第28张图片

小结:

UA 中主要包含到的信息, 就是操作系统信息 和浏览器信息, 描述了用户使用什么样的设备上网

系统不同, 浏览器不同, 设备不同, 对于某些页面的支持程度也是不一样的

现在的设备之间的差别已经比较小, 上古时期则不是.

浏览器的发展不是一蹴而就的, 是一个循序渐进的过程

  1. 最早的浏览器只支持文字
  2. 后来, 开始支持图片
  3. 再后来, 能够支持 JS
  4. 再后来, 能够支持音频/ 视频

同一个时间段内, 可以存在着好多种浏览器

# 此时, 网站的开发者就犯难了.

  1. 实现一个纯文字的网站, 确实能够保证所有人都能打开, 但是感觉太复古
  2. 实现一个支持音频视频 + JS 的网站, 旧的浏览器打不开

这时就想出了一个解决办法: 通过 UA 来收集到浏览器/ 操作系统的信息, 进一步就知道这个浏览器/ 系统都支持啥样的页面了

  • 如果是一个原始的浏览器, 就只返回了一个纯文字的页面
  • 如果是一个更先进的浏览器, 就返回一个功能丰富的页面

# 随着时间的推移, 浏览器发展发展, 殊途同归了

网站的开发者就不必再过多的纠结浏览器的兼容问题了, UA 就已经完成了历史使命了.

# 当然现在 UA 仍是有用的

可以根据 UA 来识别出 PC, 平板, 手机…分别开发出不同版本的页面

# 但这样使程序员的工作量增加了, 程序员就想了个办法, 发明了个技术, “响应式页面

通过特殊的 CSS 和 JS, 感知当前浏览器窗口的尺寸

根据不同尺寸, 重新排列页面布局, (目前很多网站都是这么做的, 写一份页面, 兼容多个设备)

# UA 的作用确实有进一步被削弱了, UA 即使失去了最初的作用, 但是至少可以用来在服务器统计用户的设备情况 (大数据时代)


Referer

我们先来看一个例子:

HTTP —— HTTP 协议中的细节(超详细!!)_第29张图片

我们通过该页面点进第一个博客, 并对其进行抓包, 我们发现有一行 Referer

HTTP —— HTTP 协议中的细节(超详细!!)_第30张图片

我们可以发现, Referer 中的网址和主页的网址是一样的.

Referer 指的就是, 当前这个页面, 是从哪个页面跳转过来的(上级页面).

# 注意 #

在浏览器地址栏直接输入一个地址, 没有 Referer

直接点收藏夹, 也没有 Referer

使用 Referfer 的典型例子: 按照点击计费 (CPC 广告)

在浏览器上有许多广告. 当我们点击广告, 就会跳转到广告主的 “落地页”, 这个点击操作, 广告主就需要付钱. (浏览器给广告主的网站导入流量了, 导入的流量就会促使一部分人去消费)

浏览器导流 => 广告主的网站曝光机会就会增加 => 促使更多的成交订单

这就就需要统计点击的次数. 根据点击的次数, 和广告主来结算广告费.

那实际点了多少次, 由谁来统计呢?

双方都统计, 然后看双方统计数量是否一致.

  • 在浏览器 A 中, 每次点击跳转, 先访问其的计费服务器, 计费服务器再返回一个重定向报文, 跳转到 广告主这边
  • 广告主, 看服务器收到的请求中, 有多少 Referer 是来自于 浏览器A 的

有没有可能, 请求中的referer被改了呢?

比如: 某公司 B, 也有自己的广告平台. 将本来是 公司A 的 referer 改成了自己的 referer. 这就相当于, 把本来是 公司A 的钱, 变成了自己了.

HTTP —— HTTP 协议中的细节(超详细!!)_第31张图片

因此务必得在技术上进行反制, 关键要点: 不能让运营商随便的来解析咱们的请求. 或者即使解析了, 也不能随意的修改. 核心就是: 加密 => HTTPS


Cookie

也是请求头中的一个重要字段, 是浏览器在本地存储数据的一种机制

HTTP —— HTTP 协议中的细节(超详细!!)_第32张图片

浏览器专门提供了特殊的 API 给网页使用, 可以让网页存储一些简单的数据

浏览器提供的持久化存储方案, 有好几种:

  1. Cookie 是最经典(最老) 的一种方案. (重点介绍)
  2. LocalStorage 是比较新的一种方案.
  3. indexDB 是更新的方案.

我们当前浏览器已经保存很多 Cookie

HTTP —— HTTP 协议中的细节(超详细!!)_第33张图片

Cookie 是按照域名维度来组织的

不同的域名下有不同的 Cookie

一个网站发起的 http 请求可能是来自于多个域名的

HTTP —— HTTP 协议中的细节(超详细!!)_第34张图片

Cookie 这里的键值对都是简单的字符串

你使用 Cookie 作为保存数据的手段, 只能存一些简单的键值对信息, 简单的字符串 (如果想让它存个图片, 存个视频…, 是万万做不到的)

比如: 可以用 Cookie 存:

  1. 上次访问页面的时间
  2. 当前网页的访问次数
  3. 当前访问页面的身份信息 (身份标识, id)

# 注意事项 #

  • Cookie 不是缓存, 是持久化存储的手段

  • 持久化存储不是缓存, 持久化存储, 是保存在硬盘上的.

  • 缓存里的数据不一定是持久化的 (也可以在内存里缓存)

  • Cookie 只在对应的域名下生效

  • 大部分路径都是 / . 意思是在整个网站下, 所有的路径都是生效的. (有些页面特殊, 需要特定的 Cookie, 这些特定的 Cookie 在其他页面中无意义)

Cookie 从哪里来的

Cookie 是存在浏览器的, 来源是服务器

HTTP —— HTTP 协议中的细节(超详细!!)_第35张图片

Cookie 到哪里去

Cookie 来自于服务器, 存储于浏览器, 还要再回到服务器

当浏览器保存了 Cookie 之后, 下次浏览器访问同一个网站, 就会把之前本地存储的 Cookie 再通过 http 请求 header 中的 Cookie 给带过去.

Cookie 典型应用场景

最常用的场景就是在客户端维持登陆状态

在某个网站上登陆成功后, 浏览器就会机制当前登录用户的身份信息, 然后接下来访问网站的其他页面, 服务器也能知道咱们是谁在登陆.

HTTP —— HTTP 协议中的细节(超详细!!)_第36张图片

很多网站都是基于这一套来实现的 (也不是 100%, 现在有很多的网站, 就不再使用 Cookie 来进行本地存储. 可以用 localStorage 之类的方法来保存)

上述介绍的这一系列流程, 是 Cookie 在实现登录验证的时候, 涉及到的情况

# 注意 # 如果我们针对某个网站抓包, 看到的 Cookie 的情况会比上述的情况更复杂一些

比如: 现在我登录我 gitee 的个人主页, 之后将 Cookie 全部移除

HTTP —— HTTP 协议中的细节(超详细!!)_第37张图片

此时我们打开 fidder , 刷新个人中心页面. 此时我们发现, 登录状态已经没有了.

HTTP —— HTTP 协议中的细节(超详细!!)_第38张图片

我们看一下响应

HTTP —— HTTP 协议中的细节(超详细!!)_第39张图片

我们发现, 将 gitee 这里的 Cookie 删了, 重新访问, 可以看到虽然未登录, 但是服务器返回了一组 Cookie 值


认识请求 “正文” body

正文中的内容格式和 header 中的 Content-Type 密切相关. 上面也罗列了三种常见的情况

1) application/x-www-form-urlencoded

2) multipart/form-data

3) application/json


(( ◞•̀д•́)◞⚔◟(•̀д•́◟ ))

以上就是今天要讲的内容了,希望对大家有所帮助,如果有问题欢迎评论指出,会积极改正!!
在这里插入图片描述
加粗样式

这里是Gujiu吖!!感谢你看到这里
祝今天的你也
开心满怀,笑容常在。

你可能感兴趣的:(JavaEE,http)