网络原理 - 11(HTTP/HTTPS - 2 - 请求)

目录

[HTTP 请求(Request)](#HTTP 请求(Request))

[认识 URL](#认识 URL)

[URL 基本格式](#URL 基本格式)

[关于 URL encode](#关于 URL encode)

认识方法(method)

[1. GET 方法](#1. GET 方法)

[2. POST 方法](#2. POST 方法)

认识请求"报头"(header)

Host

[Content-Length Content-Type](#Content-Length Content-Type)

[User-Agent(简称 UA)](#User-Agent(简称 UA))

Referer

Cookie

认识请求"正文"(body)

完!


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 还是在使用习惯上有一些区别的~~

  1. GET 习惯于把数据放到 URL 的 query string 中。POST 习惯于把数据放到 body 中。

(GET 也可以把数据放到 body,POST 也可以把数据放到 query string -- 有些可能不支持,绝大部分都支持)

  1. 语义上的区别。在标准文档中,GET 的语义是用来获取数据的,POST 的语义是给服务器传输数据的。(实际使用,当然还是程序员自己说了算~~)

  2. 关于幂等性,在标准文档中,建议 GET 请求实现幂等的,POST 无要求。

(幂等:是一种数学术语,在计算机中也很常见~~ 即每次输入的内容一定,输出的结果也一定,就称为是幂等的,如果每次输入的内容一定,输出的结果不一定,就不是幂等的)

(GET 在实际开发中,也不一定非要实现幂等,标准是这么建议的,但我们可以不听标准的建议~~)

网上的一些不太准确的相关说法:

  1. POST 比 GET 更加安全~~

论据:登录的时候,如果使用 GET,用户密码就会显示在 URL 中,此时会被别人看到,就不安全...

如今用户密码都会有一个单独的登录页面了,不会直接在 URL 中,即使是 POST ,即使没有显示子啊 URL 中,也是可以被黑客进行抓包获取的...真正保证安全性的关键在于加密!!

  1. GET 传输的数据量小(存在上限),POST 传输的数据量更大

这句话描述的是以前的情况,以前是以前,现在是现在~~

实际上,HTTP 标准文档上明确说了,对于 GET,URL 的长度是不进行限制的,只不过是之前老版本的 IE 浏览器在实现的时候,URL 的长度有限制(现在已经没有了~~)

  1. 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 中的常见选项:

请求中:

  1. application/json:body 中的数据为 json 格式,形如:

{"username":"123456789","password":"xxx","code":"aaa","uuuid":"d110a05ccde65da13"}

  1. application/x-www-form-urlencode:称为 form 表单,通过 HTML 中的 form 标签构造出来的一种格式,这种格式的特点是,把 query string 放到 body 中了

  2. multipart/form-data:当需要在表单中上传文件,或者包含二进制数据的时候使用。在 HTML 的 form 标签中需要设置 enctype="multipart/form=data"。

例如:

使用 boundary(边界标识符,如 ---------WebKitFormBoundaryrGKCBY7qhFd3TrwA)来分割不同表单数据部分。每个部分包含自身的元数据(如 Content-Disposition 指定数据类型和名称,Content-Type 指定具体的数据类型)。

响应中:

  1. text/plain 纯文本

  2. text/html html 页面

  3. text/css css 页面

  4. application/javascript js

  5. application/json

  6. image/png

  7. 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 本质上是一个浏览器这边本地持久化存储数据的机制。

浏览器作为电脑上的一个程序,是可以直接读写本地磁盘文件的,系统提供了一个 API 操作文件。注意的是,浏览器上运行的网页,理论上也是可以通过浏览器提供的 API 来读写本地的磁盘文件,但是浏览器禁止了这种做法(浏览器并没有给网页提供这样的 API) (不安全~~ 万一黑客通过网页,直接把我们 C 盘中的学习资料删了怎么办??? /哭 /哭 ~~)

但话又说回来,有些网站,是需要把一些信息保存到浏览器这边的,比如当前登录的用户身份信息~~ 浏览器退而求其次,给网页提供了 API,但这个 API 只能是有限度的存储数据,而不能随意的访问文件系统~~

HTTP 请求中的 Cookie 字段,就是把本地存储的 Cookie 信息发送到服务器这边。

HTTP 响应中会有一个 Set-Cookie 字段,就算服务器告诉浏览器你要在本地保存那些信息。

上述的请求和响应字段,都是以键值对的形式进行的(程序员可以自定义~~)

Cookie 中存储了一个字符串,这个数据可能是客户端(网页)自行通过 JavaScript 写入的,也可能是来自于服务器(服务器在 HTTP 响应的 header 中通过 Set-Cookie 字段给浏览器返回数据)

一般可以通过这个字段来实现"身份标识"的功能。(每个不同的域名下都可以有不同的 Cookie,不同网站之间的 Cookie 并不冲突~)

举个例子:

Cookie 的作用,非常类似于超市买东西时候的购物卡流程~~

  1. 注册会员(初始设置 Cookie)

当我们第一次去超市,注册称为会员之后,超市会给我们办一张会员卡,这就类比是服务器给客户端设置 Cookie。会员卡上记录了我们的信息,比如姓名,会员卡号,积分等等,这些信息就如同 Cookie 里面存储的用户标识等基础数据

  1. 首次购物(第一次请求携带 Cookie)

当我们再收银台结账的时候,收银员会扫描我们的会员卡。这就类似于客户端向服务器发起请求的时候带上了 Cookie。收银员通过会员卡,就可以知道我们是会员,会根据会员的政策给我们积分或者相关的优惠,就像服务器根据 Cookie 里面的信息,来识别出用户,并作出响应的处理,比如提供个性化的页面展示或服务~~

  1. 再次购物(后续请求携带 Cookie)

之后我们再去超市购物,结账的时候每次都出示会员卡。收银员每次都能够通过会员卡来了解到我们之前的购物记录,积分情况等,然后根据这些信息为我们提供服务~~比如提醒我们,积分快能兑换礼品了,或者根据我们的购物偏好,来推荐一些商品。这就如同客户端后续每次向服务器发送请求时,Cookie 持续发挥作用,让服务器可以基于之前的交互历史,持续为用户提供连贯,个性化的服务~~

流程图如下:

关于 Cookie 的几个重要结论:

  1. Cookie 从哪里来???

服务器返回给浏览器的。通常都是首次访问/登录成功之后。

  1. Cookie 到哪里去???

Cookie 会存储在浏览器本地主机的硬盘上。后续每次访问服务器都会带上 Cookie。不同的客户端,保存的 Cookie 是不同的,即使是同一个主机,使用不同的浏览器,Cookie 大概率也不同。

  1. Cookie 中存储什么???

Cookie 以键值对的形式对数据进行存储。这里的内容都是程序员自定义的,和 query string 一样,外人无从理解~ 不同的网站的 Cookie 是不同的~

  1. Cookie 在浏览器这边如何组织???

在硬盘本地保存,是按照不同的域名为维度,分别进行存储。

  1. Cookie 的用途是什么???

用来在客户端保存数据,其中最主要的就是保存用户的身份标识,使得服务器可以通过标识来区分用户了,一般其他的业务不会存在 Cookie 中~~

我们可以通过抓包来观察一下页面登录的过程(以 gitee 为例):

1) 清除之前的 Cookie

2) 登录操作:

登录请求:

登录响应:

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

其中我们重点看一下第二个,里面包含了一个 gitee-session-n 这样的属性,属性值是一串很长的加密之后的信息。这个信息就是用户当前登录的身份标识,也称为"令牌(token)"。

3) 访问其他页面

当我们登录成功之后,此时访问码云中的其他页面(比如个人主页),请求中就会带着刚刚获取到的 Cookie 信息。

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

比如我们此时再访问一个"我的星选集",此时请求中的 Cookie 还是和之前一样的~~

理解登录过程:

这个过程再结合我们前面去超市买东西例子:

首次进入超市后,就是打开登录页面。当我们第一次结账提供手机号信息办会员卡的时候,就是输入用户名密码,点击登录,此时就得到了一张"会员卡",这张会员卡就相当于是我们的"令牌"。

此后再去超市进行购物,积分兑换奖品等等操作,就不需要再提供手机号了,只需要凭会员卡就可以识别出我们的身份了。

当我们要搬家的时候,不想要会员卡了,就可以注销这个卡,此时我们的身份就和会员卡的关联就销毁了(类似于网站的退出登录操作)

当我们之后再搬回来,又想在超市买东西,就可以再办一张会员卡,此时就得到了一个新的令牌~~

认识请求"正文"(body)

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

完!

相关推荐
zt1985q2 小时前
本地部署开源智能家居集成平台 ioBroker 并实现外部访问( Windows 版本)
运维·服务器·智能家居
万亿少女的梦1682 小时前
基于Python的高考志愿填报辅助系统设计与实现
java·spring boot·python·mysql·vue
万亿少女的梦1682 小时前
基于SpringBoot与Vue的历史博物馆展品展示与游客管理系统设计
spring boot·mysql·vue·系统设计·博物馆管理系统
大卡片2 小时前
linux内核驱动开发
linux·运维·驱动开发
心心喵3 小时前
[linux] nohup和pm2的区别 进程保活
linux·运维·服务器
HelloWorld工程师4 小时前
新手如何快速申请SSL通配符证书...
网络协议·https·ssl
NGINX开源社区4 小时前
F5 NGINX Ingress Controller 5.3.0 新增功能
运维
灯澜忆梦5 小时前
MySQL 完整学习路线
学习·mysql
ClouGence5 小时前
保障公共安全,一线治安机构实时数据应用与实践
数据库·mysql·postgresql
Minxinbb5 小时前
TDSQL for MySQL 服务器重启操作
数据库·mysql·dba