目录
[HTTP 请求(Request)](#HTTP 请求(Request))
[认识 URL](#认识 URL)
[URL 基本格式](#URL 基本格式)
[关于 URL encode](#关于 URL encode)
[1. GET 方法](#1. GET 方法)
[2. POST 方法](#2. POST 方法)
[Content-Length Content-Type](#Content-Length Content-Type)
[User-Agent(简称 UA)](#User-Agent(简称 UA))
HTTP 请求(Request)
认识 URL
URL 基本格式
URL 不仅仅是在 HTTP 中使用,回忆想想,我们之前在 JDBC 也使用过 URL:jdbc:mysql://127.0.0.1:3306/java110?characterEncoding=utf8&useSSL=false
平时我们俗称的"网址",其实说的就是 URL(Uniform Resource Locator 统一资源定位符),描述一个互联网上的资源位置,即互联网上的每个文件都有一个唯一的 URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。(URL 的详细规则由因特网表述 RFC1738 进行约定~~)
我们上面的:https://www.baidu.com/
这是一个最简单的 URL,https 是协议的名称,www.baidu.com 是域名
我们如果抓一个百度里面的搜索内容请求如下:

此时的 URL 就不是上面那么简单了:在协议的名称,域名的后面,还跟了一长串字符~~ 称为查询字符串(query string),查询字符串中表达的意思,作为外人是无从得知的,这里面的内容就是写这个代码的程序员定义的~~
我们可以看到,在查询字符串中,也是键值对的格式。但此处的键值对,是使用 & 分割键值对,使用 = 来分割键和值~~
一个完整的 URL 结构如下:

http:协议方案名,常见的有 http 和 https,也有其他的类型(我们前面访问 mysql 的时候使用 jdbc:mysql)(可以省略,省略后默认为 http://)
user:pass:登录信息,之前是直接会把相关认证信息直接在 URL 中展示的,后来发现实在是不太安全~~ 现在都是通过单独的登陆页面来完成身份验证~~
www.example.jp:80:服务器地址,服务器端口号,这里的域名,也可以是 IP 地址,后面带有端口号,可以表示我们要访问服务器那个端口,如果 URL 中不带端口号,浏览器就会自动给一个默认的端口(这里的服务器端口,不是客户端中系统随机分配的那个),此处用什么端口作为默认值,取决于我们的协议是什么:http -- 80 https -- 443
dir/index.html:带有层次的文件路径
uid=1:查询字符串,是客户端给服务器传递信息的重要途径,这里的组织方式是按照键值对来组织的,这里面的键值对内容,是程序员自定义的~~
ch1:片段标识符,主要用于页面跳转,常用于通过不同的片段表示跳转到文档的不同章节
结合上述的 IP 地址,端口号,带层次的文件路径,查询字符串,就可以描述出一个网络资源了:
http://中北大学文韬餐厅:20/手抓饼/番茄手抓饼/?辣椒=少放\&香菜=多放
关于 URL encode
在 query string 中都是程序员自定义的键值对,但在 URL 中,本身有些特殊符号具有特特定的含义: / : ? @ .....
如果 URL 中的 query string 中也包含同样的符号,怎么办呢??? ==》 如果直接写进 query string 中,就可能会使服务器 / 浏览器解析失败!!
一个靠谱的办法,我们前面已经在代码中使用过了:对上述符号进行"转义"。包括中文字符或者是其他由 UTF-8 或者 GBK 这样的编码方式构成的字符,虽然在 URL 中没有特殊含义,但浏览器可能会把编码中的某个字节当作 URL 中的特殊符号,也需要进行转义~~
转义的规则如下:将需要转码的字符的转为 16 进制表示,前面加上 % 即可
比如我们搜索 C++:
可以看到,query string 中显示的是 C%2B%2B

我们可以通过 ASCII 码表发现,+ 的十六进度是 2B,则对应了 C++ ==》 C%2B%2B
我们也可以搜索一个女神

在上面虽然显示的 query string 直接是女神,是浏览器自动进行了解析,我们可以复制粘贴出来到文本文档就显示出来了:

我们"女神"进行 utf-8 编码:

结果相符~~
我们这里的 urlencode 编码是非常非常重要的~~ 在实际开发中,当我们要构造一个 URL 的时候,尤其是 URL 的 query string 中要包含中文的时候,务必要进行编码!!
认识方法(method)
请求的首行中,包括了 方法 URL 版本号
方法就描述了这次请求,想干啥(目的)

1. GET 方法
GET 是最常用的 HTTP 方法,常用于获取服务器上的某个资源(读操作)。在浏览器中直接输入 URL,此时浏览器就会发送出一个 GET 请求。另外,HTML 中的 link,img,script 等标签,也会触发 GET 请求。
使用 Fiddler 观察 GET 请求:
在浏览器访问百度主页,观察抓包结果:

我们可以看到,最上面蓝色的,是通过浏览器地址发送的 GET 请求,下面的
下面的一个写 baidu 域名相关的请求,有些是通过 HTML 中的 link/script/img 标签产生的。有些是通过 ajax 方式产生的。
我们选中第一条,观察请求的详细结果:

GET 请求的特点:
首行的第一部分为 GET
URL 的 query string 可以为空,也可以不为空
header 部分有若干个键值对结构
body 部分为空
2. POST 方法
POST 方法也是一种常见的方法,多用于提交用户输入的数据给服务器(例如登录页面)
我们可以登录 gitee 来进行一下抓包~

对第一个请求,点击查看详情

POST 请求的特点:
首行的第一部分为 POST
URL 的 query string 一般为空(可以不为空)
header 部分有若干个键值对结构
body 部分一般不为空,body 内的数据格式通过 header 中的 Content - Type 指定。body 的长度由 header 中的 Content - Length 指定~~
面试题:POST 和 GET 的区别:
先盖棺定论:GET 和 POST 没有本质区别。使用 GET 的场景,也可以替换成 POST,使用 POST 的场景,也能替换成 GET(这里主要是取决于程序员代码是怎么写的,尤其是服务器和客户端都是同一个程序员实现的情况~~)(部分服务器 / 部分浏览器,在某些情况下 GET 和 POST 不能完美替换,但是大部分情况下,相互替换问题一般不大~~)
但是 GET 和 POST 还是在使用习惯上有一些区别的~~
- GET 习惯于把数据放到 URL 的 query string 中。POST 习惯于把数据放到 body 中。
(GET 也可以把数据放到 body,POST 也可以把数据放到 query string -- 有些可能不支持,绝大部分都支持)
-
语义上的区别。在标准文档中,GET 的语义是用来获取数据的,POST 的语义是给服务器传输数据的。(实际使用,当然还是程序员自己说了算~~)
-
关于幂等性,在标准文档中,建议 GET 请求实现幂等的,POST 无要求。
(幂等:是一种数学术语,在计算机中也很常见~~ 即每次输入的内容一定,输出的结果也一定,就称为是幂等的,如果每次输入的内容一定,输出的结果不一定,就不是幂等的)
(GET 在实际开发中,也不一定非要实现幂等,标准是这么建议的,但我们可以不听标准的建议~~)
网上的一些不太准确的相关说法:
- POST 比 GET 更加安全~~
论据:登录的时候,如果使用 GET,用户密码就会显示在 URL 中,此时会被别人看到,就不安全...
如今用户密码都会有一个单独的登录页面了,不会直接在 URL 中,即使是 POST ,即使没有显示子啊 URL 中,也是可以被黑客进行抓包获取的...真正保证安全性的关键在于加密!!
- GET 传输的数据量小(存在上限),POST 传输的数据量更大
这句话描述的是以前的情况,以前是以前,现在是现在~~
实际上,HTTP 标准文档上明确说了,对于 GET,URL 的长度是不进行限制的,只不过是之前老版本的 IE 浏览器在实现的时候,URL 的长度有限制(现在已经没有了~~)
- GET 只能携带文本数据,POST 可以携带二进制数据
这个说法,并不是完全错误,只是有一些局限性~~
URL 通过 query string 来携带数据
query string 是只能包含文本的,是对二进制数据进行 urlencode 了,自然就成为文本了。到了服务器再进行 urldecode,就能把数据还原成二进制。
POST 请求中,bodu 中虽然可以携带二进制数据,但也不是经常携带的,很多时候是对二进制数据进行 urlencode / base64 等等方式进行转码的~~
其他方法使用较少~~
认识请求"报头"(header)
header 的整体格式也是"键值对"结构
每个键值对占一行,键和值之间使用分号进行分割~
Host
表示服务器主机的地址和端口
(URL 中已经有 Host 了,这里的 Host 和 URL 中的 IP 地址 端口什么的,绝大部分情况下都是一样的~~)
Content-Length Content-Type
Content-Length 表示 body 中的数据长度。
Content-Type 表示请求的 body 中的数据格式。
(和 body 密切相关,如果当前数据包没有 body,也就不会有这两个字段)
如果没有这两个字段,body 的请求/响应,就会直接使用空行作为分隔符了,如果有 body,空行就不是结束标志了,从空行开始来读取 body,body 要读多长就取决于 Content-Length,读完之后,这个包就结束了
Content - Type 中的常见选项:
请求中:
- application/json:body 中的数据为 json 格式,形如:
{"username":"123456789","password":"xxx","code":"aaa","uuuid":"d110a05ccde65da13"}
-
application/x-www-form-urlencode:称为 form 表单,通过 HTML 中的 form 标签构造出来的一种格式,这种格式的特点是,把 query string 放到 body 中了
-
multipart/form-data:当需要在表单中上传文件,或者包含二进制数据的时候使用。在 HTML 的 form 标签中需要设置 enctype="multipart/form=data"。
例如:

使用 boundary(边界标识符,如 ---------WebKitFormBoundaryrGKCBY7qhFd3TrwA)来分割不同表单数据部分。每个部分包含自身的元数据(如 Content-Disposition 指定数据类型和名称,Content-Type 指定具体的数据类型)。
响应中:
-
text/plain 纯文本
-
text/html html 页面
-
text/css css 页面
-
application/javascript js
-
application/json
-
image/png
-
image/jpg
.....................
补充:

我们后面自己写服务器程序返回网页,如果发现网页乱码,就可以检查一下是否是这里的编码方式没有设置或者是设置的不对~
User-Agent(简称 UA)
表示浏览器/操作系统的属性,描述了用户使用什么样的设备上网

Windows NT 10.0 Win64; x64 ==> 操作系统信息
Chrome/121.0.0.0 Safari/537.36 Edg/135.0.0.0 ==》 浏览器信息~~
上古时期,UA 是非常关键的内容,由于计算机发展迅速,不同用户使用的上网设备,差异很大,UA 就可以表明该用户上网的设备具体是什么信息,如何用户使用的是比较老的设备,返回的页面就不含新特性,确保这个页面可以正确的访问出来。如果用户使用的是新设备,返回的页面就包含新的特性,确保这个页面体验感足够好~~
随着时间推移,浏览器现在都差不多了~~ 但 UA 仍然很有用,很多网站在 PC 端和手机端,由于其设备的大小区别,返回的页面布局也会有所差异,这就是通过 UA 来进行控制的~~
Referer
表示这个页面是从那个页面跳转过来的。在浏览器中,直接输入 URL 或者点击收藏夹打开的网页,此时是没有 Refere 的

举例:
我有个朋友~~~当年做的是广告页面~~~搜索广告中,都是按照点击计费的,用户每次点击广告,负责的企业都能赚钱,所以必须要记录某个广告在某个时间段内被点击多少次。
比如说在百度中搜索"肾虚",当我们用户点击一下,百度就能到账 money~~
这个点击次数,百度和广告主都要进行统计~~
百度中,用户点击就会把请求发送到百度的计费服务台,通过记录日志就知道了~~
广告主中,就在他的服务器上记录日志,但一个广告,一般不会仅仅就找一家平台,他会找 360,搜狗等等~他怎么知道那些请求是百度的广告引流过来的呢??? ==》借助 referer 即可~~
问题来了 referer 是否会被篡改呢??? ==》 很有可能!!
因此就有了 HTTPS 的出现~~ 这个 S 其实是 SSL(网络中用于加密的协议~~)
加密就能把 header 和 body 都进行加密,网络上传输的就是密文了~~
其他人要想修改,就得先进行破解,就算能破解,也无法篡改,一旦进行修改操作,用户的浏览器就能感知到了~~~
Cookie
Cookie 本质上是一个浏览器这边本地持久化存储数据的机制。
浏览器作为电脑上的一个程序,是可以直接读写本地磁盘文件的,系统提供了一个 API 操作文件。注意的是,浏览器上运行的网页,理论上也是可以通过浏览器提供的 API 来读写本地的磁盘文件,但是浏览器禁止了这种做法(浏览器并没有给网页提供这样的 API) (不安全~~ 万一黑客通过网页,直接把我们 C 盘中的学习资料删了怎么办??? /哭 /哭 ~~)
但话又说回来,有些网站,是需要把一些信息保存到浏览器这边的,比如当前登录的用户身份信息~~ 浏览器退而求其次,给网页提供了 API,但这个 API 只能是有限度的存储数据,而不能随意的访问文件系统~~
HTTP 请求中的 Cookie 字段,就是把本地存储的 Cookie 信息发送到服务器这边。
HTTP 响应中会有一个 Set-Cookie 字段,就算服务器告诉浏览器你要在本地保存那些信息。
上述的请求和响应字段,都是以键值对的形式进行的(程序员可以自定义~~)
Cookie 中存储了一个字符串,这个数据可能是客户端(网页)自行通过 JavaScript 写入的,也可能是来自于服务器(服务器在 HTTP 响应的 header 中通过 Set-Cookie 字段给浏览器返回数据)
一般可以通过这个字段来实现"身份标识"的功能。(每个不同的域名下都可以有不同的 Cookie,不同网站之间的 Cookie 并不冲突~)
举个例子:
Cookie 的作用,非常类似于超市买东西时候的购物卡流程~~
- 注册会员(初始设置 Cookie)
当我们第一次去超市,注册称为会员之后,超市会给我们办一张会员卡,这就类比是服务器给客户端设置 Cookie。会员卡上记录了我们的信息,比如姓名,会员卡号,积分等等,这些信息就如同 Cookie 里面存储的用户标识等基础数据
- 首次购物(第一次请求携带 Cookie)
当我们再收银台结账的时候,收银员会扫描我们的会员卡。这就类似于客户端向服务器发起请求的时候带上了 Cookie。收银员通过会员卡,就可以知道我们是会员,会根据会员的政策给我们积分或者相关的优惠,就像服务器根据 Cookie 里面的信息,来识别出用户,并作出响应的处理,比如提供个性化的页面展示或服务~~
- 再次购物(后续请求携带 Cookie)
之后我们再去超市购物,结账的时候每次都出示会员卡。收银员每次都能够通过会员卡来了解到我们之前的购物记录,积分情况等,然后根据这些信息为我们提供服务~~比如提醒我们,积分快能兑换礼品了,或者根据我们的购物偏好,来推荐一些商品。这就如同客户端后续每次向服务器发送请求时,Cookie 持续发挥作用,让服务器可以基于之前的交互历史,持续为用户提供连贯,个性化的服务~~
流程图如下:
关于 Cookie 的几个重要结论:
- Cookie 从哪里来???
服务器返回给浏览器的。通常都是首次访问/登录成功之后。
- Cookie 到哪里去???
Cookie 会存储在浏览器本地主机的硬盘上。后续每次访问服务器都会带上 Cookie。不同的客户端,保存的 Cookie 是不同的,即使是同一个主机,使用不同的浏览器,Cookie 大概率也不同。
- Cookie 中存储什么???
Cookie 以键值对的形式对数据进行存储。这里的内容都是程序员自定义的,和 query string 一样,外人无从理解~ 不同的网站的 Cookie 是不同的~
- Cookie 在浏览器这边如何组织???
在硬盘本地保存,是按照不同的域名为维度,分别进行存储。
- Cookie 的用途是什么???
用来在客户端保存数据,其中最主要的就是保存用户的身份标识,使得服务器可以通过标识来区分用户了,一般其他的业务不会存在 Cookie 中~~
我们可以通过抓包来观察一下页面登录的过程(以 gitee 为例):
1) 清除之前的 Cookie

2) 登录操作:
登录请求:

登录响应:
可以看到,响应中包含了 Set-Cookie 属性

其中我们重点看一下第二个,里面包含了一个 gitee-session-n 这样的属性,属性值是一串很长的加密之后的信息。这个信息就是用户当前登录的身份标识,也称为"令牌(token)"。
3) 访问其他页面
当我们登录成功之后,此时访问码云中的其他页面(比如个人主页),请求中就会带着刚刚获取到的 Cookie 信息。

我们的请求中的 Cookie 字段也包含了一个 gitee-session-n 属性,里面的值和刚才服务器返回的值相同,后续只要访问 gitee 这个网站,就会一直带着这个令牌,直到令牌过期/下次重新登录~~
比如我们此时再访问一个"我的星选集",此时请求中的 Cookie 还是和之前一样的~~

理解登录过程:

这个过程再结合我们前面去超市买东西例子:
首次进入超市后,就是打开登录页面。当我们第一次结账提供手机号信息办会员卡的时候,就是输入用户名密码,点击登录,此时就得到了一张"会员卡",这张会员卡就相当于是我们的"令牌"。
此后再去超市进行购物,积分兑换奖品等等操作,就不需要再提供手机号了,只需要凭会员卡就可以识别出我们的身份了。
当我们要搬家的时候,不想要会员卡了,就可以注销这个卡,此时我们的身份就和会员卡的关联就销毁了(类似于网站的退出登录操作)
当我们之后再搬回来,又想在超市买东西,就可以再办一张会员卡,此时就得到了一个新的令牌~~
认识请求"正文"(body)

正文中常见的就是我们上面 Content - Type 中的一些格式内容~~
