JavaWeb | HTTP 协议请求与响应格式

一、HTTP 是什么

计算机网络核心概念:网络协议
网络协议种类非常多,其中一些耳熟能详的,IP,TCP,UD… 其中还有一个应用非常广泛的协议HTTP,HTTP 协议大概率是咱们日后开发中用的最多的协议

HTTP : (全称为 “超文本传输协议”) 是一种应用非常广泛的 应用层协议

HTTP 处于 TCP / IP 五层协议栈的应用层
HTTP 在传输层是基于TCP的 (不够严谨,HTTP/1,HTTP/2 是基于TCP最新版本是 HTTP/3 是基于 UDP,但是当下互联网上绝大部分使用的 HTTP 都是 HTTP/1.1 )

传输层协议 ,主要关注的是端对端之间的数据传输。TCP,重点关注的是可靠传输
应用层协议 ,则是站在程序应用的角度,要对传输的数据,来进行具体的使用

应用层协议,很多时候是程序猿自定制的,根据实际的需求场景,来设计协议

但是,程序猿大的圈子里,水平参差不齐
于是有些大佬就发明了一些很好用的协议,直接让大家照搬,HTTP 就是其中的一个典型代表

HTTP 虽然是已经设计好的,自身的可扩展性是非常强,可以根据实际需要,让程序猿传输各种自定义的数据信息

HTTP 具体的应用场景,大家天天都在用,只要你打开浏览器,随便打开一个网站,这个时候其实你就用到了 HTTP
或者你打开一个手机 APP,随便加载一些数据,这个时候其实你也大概率用到了 HTTP


二、HTTP 协议格式

1、协议格式

协议格式:数据具体是怎么组织的

UDP :报头 (源端口,目的端口,长度,校验和)+载荷

UDP / TCP / IP 这些协议都是属于 “二进制” 的协议,经常要理解到二进制的 bit 位

HTTP 则是一个文本格式的协议 (不需要去理解具体的二进制位,而只是理解文本的格式即可) (文本格式,所以更方便于人肉眼来观察)

如何才能看到 HTTP 的报文格式?

  • 其实可以借助一些 “抓包工具” 来获取到具体的 HTTP 交互过程中,请求和响应

TCP / UDP 这些,也是可以借助抓包工具来分析的

抓包工具,其实就是一个第三方的程序,在这个网络通信的过程中,类似于 “代理” 一样。例如我在宿舍,不想去买饭,就叫外卖送到宿舍,这个场景中,送外卖的人就是代理

JavaWeb | HTTP 协议请求与响应格式_第1张图片

请求和响应,都是要路过代理的
这个时候在代理上,就很容易获取到请求和响应的详细内容
因此,抓包工具就是一个代理,抓包工具就很容易的能够获取到,传输过程中的网络上的详细数据


2、抓包工具 Fiddler

Fiddler 是一个专门抓 HTTP 的抓包工具,没法抓到 TCP/UDP/IP… 要想抓这些,需要使用 wireshark 这样的工具

JavaWeb | HTTP 协议请求与响应格式_第2张图片

Fiddler 左侧 ,是一个列表,显示了当前抓到的所有的 HTTP / HTTPS 的数据报。HTTPS 是 HTTP 的孪生兄弟,HTTPS 就只是在 HTTP 的基础上,引入了加密机制

当选中左侧列表中的某个条目,并双击的时候,右侧就会显示这个条目的详细信息

请求:

JavaWeb | HTTP 协议请求与响应格式_第3张图片

在这里插入图片描述

这个标签页的选项,就表示了当前使用什么样的格式来显示 HTTP 请求,咱们用的最多的就是 Raw 这个选项
选择 Raw 看到的就是 HTTP 请求数据的本体
选择其他的选项,相当于 Fiddler 对数据进行了一些加工,调整了格式

点击 Row 原始数据就出来了!!
但是,太小了,看不清!! 可以点击旁边的 view in Note

JavaWeb | HTTP 协议请求与响应格式_第4张图片

以上就是 HTTP 请求的原始模样
如果你往 TCP socket 中,按照上述格式来构造数据,并写入 socket,其实本质上就相当于构造了一个 HTTP 请求

响应:

JavaWeb | HTTP 协议请求与响应格式_第5张图片

针对响应,也有很多的选项,此处要选择 Raw,才能看到本体

在这里插入图片描述

看到的本体好像是乱码 ?乱码其实是压缩之后的结果
一个服务器,最贵的硬件资源,其实是网络带宽 ,像这些HTTP响应,经常会很大,就比较占用带宽。为了能够提高效率,经常服务器会返回 “压缩之后” 的数据,由浏览器收到之后再来解压缩

JavaWeb | HTTP 协议请求与响应格式_第6张图片

点此按钮解压缩:

在这里插入图片描述

注意:

1、Fiddler 刚安装好的时候,默认没有启用 HTTPS ,如果你抓到了 HTTPS 的包,就会出现类似的情况,

在这里插入图片描述

当下网络上的大部分的网站都是 HTTPS ,如果不开启 HTTPS,其实就基本没啥可抓的了

JavaWeb | HTTP 协议请求与响应格式_第7张图片

2、Fiddler 可能会提醒你,要安装 xxx 证书 (一串英文.…….),一定要点是!!!

3、Fiddler 作为一个代理,是和其他的代理程序冲突的
如果你的电脑上也安装了其他代理程序 / 插件,就可能导致 Fiddler 失效(啥也抓不着),证你使用 fiddler的时候,要先退出相关的程序

安全问题:

  • 看对应的应用程序,是否对用户名密码进行了加密,如果没加密,就能获取到
    通过抓包,就能拿到当前的主机上的网络通信的数据
    而且,这个抓包,不一定非得在你的电脑上,也可以在通信链路的中间节点上
  • 如何解决这个问题,就需要在应用层这里加密

JavaWeb | HTTP 协议请求与响应格式_第8张图片

https:

确实是加密了,确实是在保障安全,但是 https 主要是防止篡改 ,而不是防止被窃取 [主要目的]


3、HTTP 请求格式

JavaWeb | HTTP 协议请求与响应格式_第9张图片

请求分成 4 个部分:

  • 请求行(首行) ,包含三个部分:

    • 1、 HTTP 的方法,方法大概描述了这个请求想干什么,``GET` 意思就是想从服务器获取到某个东西
    • 2、 URL 描述了要访问的网络上的资源具体是在哪
    • 3、 版本号, HTTP/1.1 表示当前使用的 HTTP 的版本是 1.1,1.1 是当下最主流的版本,还可能是 1.0 / 2 / 3
  • 请求头 (header),包含了很多行

    • 每一行都是一个键值对
    • 键和值之间使用 :空格 来分割
      键值对,计算机中的一个非常非常非常重要的概念
    • 这里的键值对个数是不固定的 (有可能多,也有可能少),不同的键和值,表示的含义,也不同 (后面会介绍一些常见的键值对的含义
  • 空行 :相当于请求头的结束标记
    类似于链表的 null

  • 请求正文(body) :可选的,不一定有

使用 fiddler 的一个小技巧:

  • 左侧的列表会一直持续的抓到新的结果 ,很快列表就会很大 (很多网站都在不停的和服务器交互,甚至说你电脑上的有些其他程序,也在偷偷的和人家的服务器使用 HTTP 交互)
  • 很多时候要进行清屏 ,选中一条记录,然后 ctrl + a 全选,然后按 delete 删除

一个简单的点击登录操作,就会让浏览器和码云服务器之间进行 N 多次交互,这是常态
就需要找到咱们想关注的请求,响应

JavaWeb | HTTP 协议请求与响应格式_第10张图片


4、HTTP 响应格式

JavaWeb | HTTP 协议请求与响应格式_第11张图片

  • 首行 :包含了3个部分

    • 1、 版本号 HTTP/1.1

    • 2、200 状态码,描述了这个响应,是一个表示 “成功的” 还是 "失败的”,以及不同的状态码,描述了失败的原因

    • 3、OK 状态码的描述 ,通过一个 / 一组简单的单词,来描述当前的状态码的含义

  • 响应头(header)

    • 也是键值对结构,每个键值对占一行,
    • 每个键和值之间使用 :空格 来分割,
    • 响应头中的键值对个数,也是不确定的。不同的键值对表示不同的含义
  • 空行
    表示响应头的结束标记

  • 响应正文(body)

    • 服务器返回给客户端的具体数据
    • 这里的东西可能有各种不同的格式 ,其中最常见的格式,html !!

三、HTTP 请求 (Request)

1、URL

  • 平时我们俗称的 “网址” 其实就是说的 URL (Uniform Resource Locator 统一资源定位符)
  • 互联网上的每个文件都有一个唯一的URL,既要明确主机是谁,又要明确取主机上的哪个资源

1.1、URL 基本格式

JavaWeb | HTTP 协议请求与响应格式_第12张图片

1、协议方案名:

  • 描述了当前这个 URL 是给哪个协议来使用的

  • http://给HTTP用的
    https://给HTTPS 用的
    jdbc:mysql://给jdbc:mysql使用的

2、登录信息:

  • 这个部分现在很少会用到,上古时期的时候,上网,会在这里体现用户名密码

3、服务器地址

  • 当前要访问的主机是什么,这里可以是一个 IP 地址,也可以是域名

4、服务器端口号

  • 表示当前要访问的主机上的哪个应用程序 (端口号大部分情况下是省略的)
  • 省略的时候,不是说没有,而是浏览器会自动赋予一个默认值 ,对于 http 开头的 URL,就会使用 80 端口作为默认值,对于 https 开头的 URL,就会使用 443 端口作为默认值

5、带层次的文件路径

  • 文件路径,描述了当前要访问的服务器的资源是啥
  • 虽然请求的 URL 中,写的是一个文件路径,但是不一定服务器上就真存在一个对应的文件。这个文件可能是一个真实的,在磁盘上存在的文件,也可能是虚拟的,由服务器代码,构造出的一个动态数据

上述的 IP地址+端口+带层次的文件路径 其实就描述了一个网络上具体的资源,但是在这个基础之上,还可以携带一些其他的要求,也就是后面的参数

6、查询字符串

  • 本质上是浏览器 / 客户端,给服务器传递的自定义的信息,相当于对获取到的资源提出了进一步的要求

  • 查询字符串的内容,本质上也是键值对结构,完全是程序猿自己定义的 ,外人不认识。例如:spm=1001.2014.3001.5502,键:spm,值:1001.2014.3001.5502,多个键值对以取地址符分隔

  • 查询字符串 和 路径 之间使用 ? 来分割

  • 路径就是 / ,查询字符串(query stirng) 没有 https://www.sogou.com/

    路径 web,查询字符串是后面到结束, https://www.sogou.com/web?query=fiddler&_asf=www.sogou.com&_ast=&w=01015002&p=40040108&ie=utf8&from=index-nologin&s_from=index&oq=&ri=0&sourceid=sugg&suguuid=&sut=0&sst0=1652343501136&lkt=0%2C0%2C0&sugsuv=1623569485720894&sugtime=1652343501136

    路径qq_56884023/article/details/124481401,查询字符串是后面到结束 https://blog.csdn.net/qq_56884023/article/details/124481401?spm=1001.2014.3001.5502

7、片段标识符

  • 描述了要访问当前 html 页面中哪个具体的子部分,能够控制浏览器滚动到相关位置

URL 中的可省略部分:

  • 协议名: 可以省略, 省略后默认为 http://
  • ip 地址 / 域名: 在 HTML 中可以省略(比如 img, link, script, a 标签的 src 或者 href 属性). 省略后表示服务器的 ip / 域名与当前 HTML 所属的 ip / 域名一致.
  • 端口号: 可以省略. 省略后如果是 http 协议, 端口号自动设为 80; 如果是 https 协议, 端口号自动设为 443.
  • 带层次的文件路径: 可以省略. 省略后相当于 / . 有些服务器会在发现 / 路径的时候自动访问/index.html
  • 查询字符串: 可以省略
  • 片段标识: 可以省略

URL 小结:

  • 对于 URL 来说,里面的结构看起来比较复杂,其实最重要的,和开发最关系紧密的,主要就是四个部分
    • ip 地址 / 域名
    • 端口号(经常是小透明)
    • 带层次结构的路径
    • query string 查询字符串 (这两个是和写代码密切相关的!!!)

1.2、URL encode / decode

  • 当 query string 中如果包含了特殊字符,就需要对特殊字符进行转义
  • 这个转义的过程,就叫做 url encode。反之,把转义后的内容还原回来,就叫做 url decode

url 里面是有很多特殊含义的符号的,/: ? &= … 这些符号都是在 URL 中具有特定含义的
万一,query string 里也包含这类特殊符号,就可能导致URL被解析失败!!!

当我们在 sogou 中搜索 C++ 的时候,可以看到,URL 中的 query string 里面,有一个键值对,就表示了查询词内容

https://www.sogou.com/web?query=C%2B%2B&_ast=1652345880&_asf=www.sogou.c …

%2B 其实就是 + 通过url encode 转义之后得到的结果。字符 + 的 ascii 的 16 进制表示,正是 2B (B 就是十六进制符号,相当于十进制的 11)

在实际开发的时候,尤其是前后端交互的时候,尤其是需要通过 URL 给服务器传递一些信息的时候,一定要针对里面的特殊符号进行 url encode。不仅仅是标点符号,还有中文字符
如果不转义,就可能会带来问题

  • 一个中文字符由 UTF-8 或者 GBK 这样的编码方式构成,虽然在 URL 中没有特殊含义,但是仍然需要进行转义,否则浏览器可能把 UTF-8/GBK 编码中的某个字节当做 URL 中的特殊符号
  • 转义的规则如下:将需要转码的字符转为 16 进制,然后从右到左,取4位 (不足4位直接处理),每2位做一位,前面加上%,编码成%XY格式,每个字节都分别这样处理

例如搜狗的 a 标签,有个 href 属性,包含了用户的查询词,如果页面中没有对中文查询词进行 urlencode 处理,就会导致在有些浏览器上,用户点击之后,不能正确跳转

JavaWeb | HTTP 协议请求与响应格式_第13张图片


2、方法

这里只是罗列到了 1.1,后续的 2 3 版本暂时不考虑

JavaWeb | HTTP 协议请求与响应格式_第14张图片

HTTP 协议的方法非常多!!!
但是最最常用的,也就是 GETPOST。GET 独占八斗,POST 占一斗,剩下的其他的方法,分这一斗

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

2.1、语义

HTTP 中引入这些方法,初衷 是为了表示不同的"语义",语义:是否有特定的含义

例如 HTML:h3, p, a, img… 语义化标签,div span 无语义标签

理想很丰满,但是现实很骨感
设计 HTTP 的大佬希望程序猿能够按照 HTTP 语义来使用这里的各种方法
但是随着时间的推移,使用就走形了,现在大家写代码,基本都是 GET / POST 一把梭,基本没咋考虑语义的事情
正因为如此,也就导致了多种 HTTP 方法之间的界限,就变的模糊了

GET 也可以给服务器送个东西,POST 也可以从服务器拿个东西


2.2、经典面试题:谈谈 GET 和 POST 的区别

第一句话,先盖棺定论!! GET 和 POST 没有本质区别!!!
具体来说,相当于是 GET 能使用的场景,也能替换成 POST,POST 使用的场景,也能替换成 GET但是细节上,还是有一些区别的

  1. 语义上的区别
    GET通常用来取数据,POST通常用来上传数据。现状是,GET也经常用来上传数据,POST也经常用来获取数据

  2. 通常情况下,GET 是没有 body,GET 通过 query string 向服务器传递数据
    通常情况下,POST 是有 body 的,POST 通过 body 向服务器传递数据,但是 POST 没有 query string

    • 如果我就想让 GET 有 body,(自己构造一个带 body 的 GET 请求),或者就想让 POST 带有 query string,完全可以
      不是强制性的区别,只是习惯用法,你可以遵守习惯,也可以打破习惯。像有些公司,统一都是使用 POST 来处理所有的请求
  3. GET 请求─般是幂等的,POST 请求一般是不幂等的, (也不是强制要求,而是建议)

    • 幂等: 是数学上的术语,每次你相同的输入,得到的输出结果是确定的。不幂等:每次你相同的输入,得到的结果不确定
  4. GET 可以被缓存,POST 不能被缓存

    • 提前把结果记住,如果是幂等的,记住结果是很有用的,节省了下次访问的开销。如果不是幂等的,就不应该去记
      能不能缓存和能不能幂等是有关联的,如果请求本身都不是幂等,就不能缓存

JavaWeb | HTTP 协议请求与响应格式_第15张图片

例如获取到的广告数据,虽然也是通过 GET 拿到的,但是绝对不能进行缓存!! 必须要实时计算,得保证合适的用户出合适的广告,出的广告也得符合广告主的投放规则

注意:网上最典型的错误:

  • GET 请求传递的数据长度有上限 (URL 有上限),POST 没有上限
    错误的!!! HTTP标准文档中,明文规定,标准本身不限制 URL 的长度 (网上流传这个说法的原因是,上古时期的浏览器实现,没有完全遵守标准导致的… 不适合于现代的浏览器…)

3、请求 “报头” (header)

  • header 里面是一些键值对,不同的键值对表示了不同的含义
  • 当前这里的键值对种类很多,以下是一些简单常见的

3.1、Host

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

Host: www.sogou.com。域名是可以通过 DNS 来转成 IP 地址的


3.2、Content-Length、Content-Type

  • Content-Length 表示 body 中的数据长度
  • Content-Type 表示请求的 body 中的数据格式

这两个属性是在描述 body ,如果你的请求里就没有 body(GET),也就不需要这两个字段了!!!
一般 POST 都是带 body,一般登录都是基于 POST 来实现的!!

JavaWeb | HTTP 协议请求与响应格式_第16张图片

为什么登录,是使用 POST 实现? 使用 GET 能不能实现登录呢?? 使用 GET 是完全可以实现登录功能的!!

为啥还主要使用POST?
登录肯定就要给服务器传递用户名和密码,如果是 GET,用户名密码习惯上就会放到 URL 的 query string 中来传递,
此时浏览器的地址栏里的路径,就可能变的很长一串)
(这个时候,用户体验可能就不太好)

尤其是早期的很多网站,就是把密码明文提交的
如果密码就明文的出现在 URL 中,其实就看起来就非常不好

POST 数据在 body 中,用户是不能直接看到的,body 里你放啥东西对于用户的影响都是非常小的

网上有种说法:使用 POST 实现登录,是因为 POST 比 GET 更安全,这种说法是完全不对的,安全不安全,取决于你的数据是否是明文传输,是否是加密过了

常见选项:

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

    • title=test&content=hello
  2. 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 …
      ------WebKitFormBoundaryrGKCBY7qhFd3Trw

  3. application/json : 数据为 json 格式. body 格式形如

    • {“username”:“123456789”,“password”:“xxxx”,“code”:“jw7l”,“uuid”:“d110a05ccde64b16a861fa2bddfdcd15”}
    • 第三种最常见请求中的 body 的格式,json (1.自定义应用层协议 2.js 的对象)

关于 Content-Length 的补充:

HTTP 也是基于 TCP 的协议
TCP 是一个面向字节流的协议,粘包问题 => 合理设计应用层协议,来明确包和包之间的边界!!

这两个在 HTTP 中都有体现:

  1. 使用分隔符
    • 如果当前有若干个 GET 请求到了 TCP 接收缓冲区中了…
      应用程序读取请求的时候,就以空行为分隔符
  2. 使用长度
    • 如果当前是有若干个 POST 请求,到了TCP缓冲区了
      这个时候,空行后面还有 body,当应用程序读到空行之后,就需要按照 Content-Length 表明的长度,继续读若干长度的数据

3.3、User-Agent (简称 UA)

表示的是,当前用户是在拿一个啥样的东西来上网

JavaWeb | HTTP 协议请求与响应格式_第17张图片

主要是 操作系统信息+浏览器信息

上古时期,浏览器处在一个飞速进步的状态,最开始的浏览器,只能显示文本
再后来,能够显示图片了
再后来,能够显示各种复杂的样式了,再后来,能够加载 js 实现交互了
再后来,能够支持各种多媒体了(播放视频啥的

以前的时候,由于浏览器发展很快,导致市场被严重割裂了

一部分用户,用的是比较老的浏览器(只能显示文本)
—部分用户,用的是比较新的浏览器(能够支持js )

这个时候就给网站开发人员带来了挑战
为了解决这个问题,聪明的程序猿就想到了,让浏览器发送的请求中,来个自报家门
服务器就可以根据浏览器中的这个自报家门的信息,就可以做出区分了

在2022年的今天,主流浏览器的功能已经差别很小 (十年前,浏览器兼容性,还是前端开发要考虑的大问题),UA 这个字段起到的作用就已经不那么大了
但是随着当下移动互联网的到来,UA 现在又有了新的使命:用来区分是 PC 端 还是 手机端
最大的区别,就是屏幕的尺寸和比例!!!
屏幕尺寸是远远小于PC端 (一般手机端的网页,就得把按钮之类的设计的大点),屏幕比例 PC 都是宽屏,手机都是窄屏,比例不同就导致页面布局就得不同
因此,服务器就可以根据 UA 来区分当前是手机还是电脑,如果是手机就返回手机版的网页,如果是电脑就返回电脑版的网页

User-Agent 之所以是这个样子是因为历史遗留问题,可以参考
User-Agent 的故事: http://www.nowamagic.net/librarys/veda/detail/2576


3.4、Referer

  • 表示了当前的页面,是从哪个页面,跳转过来的
  • Referer 不是一定有的,如果你是通过浏览器地址栏直接输入地址,或者直接点收藏夹,这个时候是没 referer

Referer: https://gitee.com/login

Referer 这个东西也是一个非常有用的字段,广告系统,按点击来计费!!

在这里插入图片描述

只要用户在搜索结果中,点击了,这个点击就会触发计费!! (广告主,就得给搜狗钱!!) CPC 广告(按点击计费)

既然是按照点击计费,一天/一个月这个广告一共被点了多少次? 得有一个明确的统计!!!

ROI投入产出比,这个统计,是搜狗统计,还是广告主统计?? 实际上就是双方都统计

搜狗统计:每次点击请求,其实都会先访问搜狗的服务器,再跳转到广告主的页面

JavaWeb | HTTP 协议请求与响应格式_第18张图片

一点击,就把这个请求发给了搜狗的计费服务器 (bill server),搜狗就可以按照这个服务器上收到的数据来进行统计

广告主统计:广告主的网站上,也是能记录一些日志的

一个广告主,可能在多个平台投广告
广告主就可以 通过 Referer 来区分当前的请求是哪个广告平台导入过来的流量

在这里插入图片描述

是否可能有一种操作,把 HTTP 请求中的 Referer 给篡改了?本来是搜狗,给改成别的了
这种可能性是完全有的,而且一度非常猖獗!
这个事情,谁有能力干? 谁有动机干? => 运营商

运营商也有自己的广告平台。

网络基础设施(路由器交换机) 都是运营商提供的,网络流量经过了人家的设备,人家的设备就可以对你的请求进行抓包,并且进行修改操作

这个情况在2015年之前,是非常普遍的。这里,官司该打要打,但是也要通过技术手段进行反制:HTTPS
2015年之前,百度,搜狗 等广告平台,都是用 HTTP 协议的,(当年网络上的 HTTPS 非常少),于是这些大的互联网公司纷纷开始升级,升级到了 HTTPS


3.5、Cookie

浏览器,为了安全,默认情况下是不能让页面的 js 访问到用户电脑上的文件系统的
假设某个网页上,包含恶意代码,不小心一点,就可能触发这个恶意代码,把你电脑上的一些文件全给删了!!!

但是这样的安全限制,也带来了一些麻烦,有时候,确实又需要让页面这里持久化存储一些数据,方便后续访问网站

其中,最典型的,就是需要存储用户当前的身份信息
当用户在登录页面完成身份认证之后,此时服务器就会给浏览器返回一个用户的身份信息,浏览器把这个信息就保存到了一个特定的位置上,后续再访问同一个网站的其他页面的时候,浏览器再自动的带上这个身份信息,服务器就能识别了

因此当前就是采取这样的策略!!!
虽然不能让页面的 js 访问你的整个磁盘数据,但是可以单独给浏览器分配一个小黑屋,js 代码就可以在这个小黑屋里随便折腾,这里的折腾,就不会影响到你磁盘上的其他的学习资料

这里的小黑屋,有多种不同的形式。
其中 Cookie 是一个比较古老,也比较经典的形式,现代浏览器也支持一些其他的本地存储的方案

Cookie 就是浏览器给页面提供的一种能够持久化存储数据的机制 ,持久化指的就是,数据不会因为程序重启或者主机重启 而丢失 (写到磁盘里)

Cookie具体的组织形式:

  1. 按照域名来组织,针对每个域名,分别分配一个小房间。我访问搜狗,浏览器就会给 sogou 这个域名记录一组 cookie,我访问码云,浏览器也就会给码云也记录一组 cookie
  2. 一个小房间里面,又会按照键值对的方式来组织数据

JavaWeb | HTTP 协议请求与响应格式_第19张图片

Cookie 数据从哪里来的:其实是服务器返回给客户端的

包含了一组这样的 header,就是服务器完成身份认证之后,就给客户端返回了一些具体的信息,信息就是通过 Set-Cookie 这样的响应报头来表示的

在这里插入图片描述

Cookie 里面保存身份信息,这件事,就类似去医院看病

  • 去医院,第一件事,要先挂号
    在挂号处,除了要交钱之外,人家还会给你一个就诊卡,给你就诊卡的时候人家工作人员会问你,要你的具体信息(姓名,身份证号码,电话号码…

  • 后续看病的过程中,这个就诊卡就起到了至关重要的作用
    先来到了儿科诊室,医生在看病之前,要先刷一下我的就诊卡,刷卡就是在获取到我的身份信息,身份信息里除了基本信息之外,还有以往病例

  • 经过了一番诊断,医生给我开了一些单子:
    去检验科,抽血化验,做血常规。还是拿着我的就诊卡一刷,这一刷就获取到了我的基本信息,和刚才医生给我开的具体的化验内容去放射科

    排个 X 光片。也是拿着我的就诊卡—刷,就知道要拍一个啥样的片子…

  • 在上述过程中,我手里的就诊卡就是 cookie !!!
    虽然就诊卡上面可以存储一些信息,但是保存的数据量是有限的
    真正保存我的这些信息,并不是这个卡,而是放到了医院的服务器上,而卡上,只需要存储我的一个身份标识 (存一个用户 id )

这些关键信息,存储在服务器上,管这个东西称为 “session”,会话

服务器这里管理着很多很多的 session
每个 session 里面都存储了用户的关键信息 (基本信息,要做的检查,以往病例…),每个 session 也有一个 sessionld (会话的标识)

就诊卡上其实存储的是这个会话的 id

JavaWeb | HTTP 协议请求与响应格式_第20张图片

这个东西看起来就很像是一个 sessionld
服务器就可以根据这个数据,来找到用户对应的会话,进一步获取到用户的详细情况
cookie 这里存的键值对,也是和 query string 类似,也都是程序猿自定义的,外人不知道,看不懂

总结:

  • Cookie 是浏览器提供的一个持久化存储数据的机制
  • Cookie 的最重要的应用场景,就是存储会话 id,进一步的让访问服务器的后续页面的时候,能够带上这个 id,从而让服务器能够知道当前的用户信息 (服务器上保存用户信息这样的机制就称为 Session 会话)
  • Cookie 能不能用来存别的信息?? 当然也是阔以的!!! 具体想存啥,就存啥,都是程序猿自定义的!!!

关于 Session 会话的理解:QQ 的消息列表,就相当于 “会话列表”,这里的聊天记录,就相当于用户的详细信息了


4、正文 body

正文中的内容格式非常灵活,取决于 header 中的 Content-Type
下面可以通过抓包来观察这几种情况:

  1. application/x-www-form-urlencoded 和 query string 一样,键值对结构,键值对之间使用 & 分隔,键和值之间使用 = 分割,并且要进行 url encode

    • 抓取码云上传头像请求

      avatar=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAPgAAAD4CAYAAADB0Ss
      LAAAg…

  2. multipart/form-data 上传文件

    • 抓取教务系统的 “上传简历” 功能

      ------WebKitFormBoundary8d5Rp4eJgrUSS3wT

      Content-Disposition: form-data; name=“file”; filename=“李星亚 Java开发工程师.pdf”
      Content-Type: application/pdf

      %PDF-1.7

      1 0 obj
      <> /Outlines 5 0 R /Pages 2 0 R /Type /Catalog>>
      endobj
      3 0 obj
      < (D:20201122145133+06’51’) /Creator ( W P S e [W) /Keywords () /ModDate
      (D:20201122145133+06’51’) /Producer () /SourceModified (D:20201122145133+06’51’)
      /Subject () /Title () /Trapped /False>>
      endobj
      13 0 obj
      <>
      endobj

  3. application/json{} 构成的键值对,键值对之间使用逗号分割,键和值之间使用 : 分割

    • 抓取教务系统的登陆页面

      {“username”:“123456789”,“password”:“xxxx”,“code”:“u58u”,“uuid”:“9bd8e09ea27b48cdacc6a6bc41d9f462”}

抓包是一个很有用的技能

  • 理解 HTTP
  • 调试一个 web 程序
  • 实现一个爬虫
    • 自己写一个 HTTP 客户端,来模拟人的操作,来自动从网站上获取到一些内容
      任何一个编程语言,只要能操作网络,都可以写爬虫,使用 Java 写爬虫,也是很常见的操作
    • 每个网站会提供一个 robot.txt 这样的文件,这个文件告诉你说那些资源是可以合法的进行爬取,理论上来说,只要你爬取了这个人家给的白名单之外的内容,都算非法行为

四、HTTP 响应

1、状态码 (status code)

表示这次请求是成功还是失败,以及失败的原因是什么

HTTP提供的状态码,有很多:

200 OK 这是一个最常见的状态码, 表示访问成功

404 Not Found 要访问的资源不存在

sogou.com/1.html:

JavaWeb | HTTP 协议请求与响应格式_第21张图片

bilibili/1.html:

JavaWeb | HTTP 协议请求与响应格式_第22张图片

403 Forbidden 虽然资源有,但是你没有权限使用(丑拒)

HTTP/1.1 403 Forbidden

这个情况,你去外面的网站上抓包,很难遇到… 但是如果后面自己写网站后台,这个就很容易出现
例如,尝试使用 GET 来访问人家的服务器,但是可能人家只支持 POST,于是就会返回 405

500 Internal Server Error 服务器自己出问题了,意味着出现 bug,外面的服务器上看到这种情况的概率也是比较低的,但是咱们后面自己写代码,也是很容易出现这个情况的

504 Gateway Timeout 服务器太繁忙了

302 Move temporarily 重定向

在登录过程中,非常典型的情况

这个词在计算机的很多场景中都会涉及到,不仅仅是 HTTP
但是虽然在不同场景中细节上有差异,但是表示的核心含义,都是呼叫转移
呼叫转移:中国移动,运营商这里可以办理的一个业务,有人拨打我的旧号码,就会自动的转接到我的新号码上

HTTP/1.1 302 Found
Location: https://gitee.com/xxxxxxxxx/kodi-source
Location 就描述了接下来要跳转到哪里!!
在重定向响应中,一般都是需要 Location 属性的

HTTP 状态码的种类:

JavaWeb | HTTP 协议请求与响应格式_第23张图片

2 开头,都属于成功 —— 200

3 开头,都属于重定向 —— 301 302

4 开头,都属于客户端出现错误了 —— 404 403

5 开头,都属于服务器出现错误了 —— 500 504

1 和 6 开头的状态码非常少,也很少见

在这些状态码中,其实还有一个特别的,418
418 虽然在搜狗百科上没有,但是确实存在于 HTTP 标准文档中,
描述:l am a teapot 俺是一个茶壶
是一个彩蛋 (程序猿的幽默)

但是实际开发中,谨慎搞彩蛋,一个典型的负面案例:
前端领域有一个 ant design 开源组件 (阿里搞的),之前这个还是非常火的,很多人都在用
这个作者就搞了一个彩蛋,在圣诞节这天会触发这个彩蛋,
使用了 a d 的组件,就会在圣诞节这天,上面出现一个 “小云彩” 这样的小 logo
客户表示,这个按钮为什么被狗啃了一半


你可能感兴趣的:(JavaEE,http,网络协议,网络)