目录

1.什么是HTTP协议?

2.HTTP的协议格式

使用fiddler抓包工具

理解代理

查看请求内容

3.HTTP请求(Request)

认识URL

URL encode

认识method

GET方法

POST方法

经典面试题:POST和GET之间的典型区别

其它方法

认识请求 “报头” (header)

Host

Content-Length

Content-Type

User-Agent

cookie

认识请求 “正文” (body)


1.什么是HTTP协议?

http协议是应用层最广泛使用的协议之一,用来浏览器和web服务器之间的交互,它是浏览器和服务器交互的桥梁

HTTP 往往是基于传输层的 TCP 协议实现的. (HTTP1.0, HTTP1.1, HTTP2.0 均为TCP, HTTP3 基于 UDP 实现)

目前我们主要使用的还是 HTTP1.1 和 HTTP2.0 . 当前讨论的 HTTP 以 1.1 版本为主

当我们在浏览器中输入一个 “网址” (URL) 时, 浏览器就给服务器发送了一个 HTTP 请求, 服务器返回了一个 HTTP 响应. 这个响应结果被浏览器解析之后, 就展示成我们看到的页面内容. (这个过程中浏览器可能会给服务器发送 多个 HTTP 请求, 服务器会对应返回多个响应, 这些响应里就包含了页面 HTML, CSS, JavaScript, 图片, 字体等信息)

“超文本” 的含义, 就是传输的内容不仅仅是文本(比如 html, css 这个就是文本), 还可以是一些其他的资源, 比如图片视频音频等二进制的数据

2.HTTP的协议格式

使用fiddler抓包工具

HTTP 是一个文本格式的协议,要理解http交互的详细过程,可以借助第三方工具–fiddler来进行抓包,此工具专注于抓’http’使用起来更方便,没有其它的杂项

浏览器搜索fiddler下载安装,下载地址:https://www.telerik.com/download/fiddler

点击下载, 我们当前使用Classic版本,它是免费的

下载成功

安装

我们打开fiddler

fiddler本质是一个代理程序,使用的时候有两个注意事项

1.可能和别的代理程序冲突,使用时要关闭其它的代理程序(包括一些浏览器插件)

2.要想正确抓包,还需要开启https功能,https后续会介绍,是基于http的进化版本,当下互联网绝大部分的服务器都是使用https协议的,fiddler默认不能抓到https的包,需要手动启用一下https并且安装证书

如何开启https” />

勾上这几个复选框,首次勾选会会弹出来对话框,询问你是否要安装对应的证书,选择是进行安装

证书相关的知识后续会介绍

理解代理

如何理解代理” />

正向代理代表着客户端的代理,反向代理代表着服务器端的代理

现在我们访问一个网站

看一下抓包结果,出现了https

这些结果就是浏览器访问百度时产生的http请求,浏览器打开一个页面,对应的http请求可能是一个,也可能是多个,我们最关注的是请求百度的首页页面,其它的请求都是基于这个请求产生的,也就是百度主页中的其它代码又产生了别的请求

这个圈起来的蓝色抓包结果是百度的主页页面,是html页面,绿色的是js.其他颜色的是反回数据

查看请求内容

如何查看请求内容” />

在右侧详细信息上方选择Raw,里面现实的是http最原始的效果.因为http请求是有一定格式的,fiddler会按照格式解析,呈现出不同的效果

点击右下角View in Notepad用记事本显示内容

抓包结果:

首行: [方法] + [url] + [版本]

Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分 结束

Body: 空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有 一个Content-Length属性来标识Body的长度;

观察抓包结果,可以看到,当前http请求,其实是一个行文本格式的数据,相比于tcp的二进制格式来说,更方便与用户来观察

再看看响应的数据,点击右下角的]Raw,用记事本查看

这些文本数据就是百度主页的html中的内容

可以看到响应数据也是文本,但是有的服务器会对响应进行压缩,也就是变成二进制乱码,压缩是为了节省带宽(带宽相比于cpu,内存,硬盘是最贵的)将数据压缩之后,文件体积就变小了,更容易进行传输,就像我们平常用的压缩包之类,虽然会花费一定的cpu资源进行解压缩,但是节省了大量的带宽!

如何理解压缩” />

抓包结果:

首行: [版本号] + [状态码] + [状态码解释]

Header: 请求的属性, 冒号分割的键值对;每组属性之间使用\n分隔;遇到空行表示Header部分 结束

Body: 空行后面的内容都是Body. Body允许为空字符串. 如果Body存在, 则在Header中会有 一个Content-Length属性来标识Body的长度; 如果服务器返回了一个html页面, 那么html页 面内容就是在body中.

总结:HTTP协议格式

有了上述基础,我们就可以研究http协议的协议格式了,学习一个协议就是学习它的报文格式

我们来看刚抓取的百度主页请求:

3.HTTP请求(Request)

GET https://www.baidu.com/" />https://www.baidu.com/?tn=49055317_28_hao_pg:URL

HTTP/1.1:版本号

首行=方法+URL+版本号

认识URL

平时我们俗称的 "网址" 其实就是说的 URL (Uniform Resource Locator 统一资源定位符).标识了互联网上的唯一资源的位置,资源在哪个服务器的哪个目录下的某个文件,是互联网上的具体地址

实际上,URL也可以起到身份标识的作用,可以视为一个URI,开发中这两个词就混用了

看一个具体的URL

https://mp.csdn.net/mp_blog/creation/editor?not_checkout=1

https : 协议方案名. 常见的有 http 和 https, 也有其他的类型. (例如访问 mysql 时用的 jdbc:mysql )

user:pass : 登陆信息. 现在的网站进行身份认证一般不再通过 URL 进行了. 一般都会省略

mp.csdn.net:服务器地址. 此处是一个 "域名", 域名会通过 DNS 系统解析成一个具体的 IP 地址. (通过 ping 命令可以看到, v.bitedu.vip 的真实 IP 地址为 118.24.113.28 )

使用 ping 命令查看域名对应的 IP 地址

1. 在开始菜单中输入 cmd , 打开 命令提示符

2. 在 cmd 中输入 ping v.bitedu.vip , 即可看到域名解析的结果.

端口号: 上面的 URL 中端口号被省略了. 当端口号省略的时候, 浏览器会根据协议类型自动决定使用 哪个端口. 例如 http 协议默认使用 80 端口, https 协议默认使用 443 端口

mp_blog/creation/editor:带层次的文件路径

not_checkout=1:查询字符串(query string). 本质是一个键值对结构. 键值对之间使用 & 分隔. 键和值之间使用 = 分隔.(query string 中的内容是键值对结构. 其中的 key 和 value 的取值和个数, 完全都是程序猿自己约定的. 我们可以通过这样的方式来自定制传输我们需要的信息给服务器.)

片段标识:此处省略了,片段标识主要用于页面内跳转,就是通过不同的片段标识跳转到页面内不同的章节

URL中可以省略的部分

协议名:省略后默认为http://

ip地址/域名:在 HTML 中可以省略(比如 img, link, script, a 标签的 src 或者 href 属性). 省略后表示服务器的 ip / 域名与当前 HTML 所属的 ip / 域名一致

端口号: 可以省略. 省略后如果是 http 协议, 端口号自动设为 80; 如果是 https 协议, 端口号自 动设为 443

带层次的文件路径: 可以省略. 省略后相当于 / . 有些服务器会在发现 / 路径的时候自动访问 /index.html

查询字符串: 可以省略

片段标识: 可以省略

URL encode

像/" />

例如:#被转义成了%23

认识method

实际开发中,这些方法大部分都是用不到的.最常见的就两个:GET和POST方法

GET方法

GET 是最常用的 HTTP 方法,常用于获取服务器上的某个资源

在浏览器中直接输入 URL, 此时浏览器就会发送出一个 GET 请求. 另外, HTML 中的 link, img, script 等标签, 也会触发 GET 请求,后面我们会学习使用 JavaScript 中的 ajax 也能构造 GET 请求

打开 Fiddler, 访问百度, 观察抓包结果.

圈起来的Host是通过浏览器地址栏发送的 GET 请求,观察请求的详细结果

GET https://www.baidu.com/" />

GET 请求的特点

首行的第一部分为 GET

URL 的 query string 可以为空, 也可以不为空.

header 部分有若干个键值对结构.

body 部分为空

POST方法

POST 方法也是一种常见的方法. 多用于提交用户输入的数据给服务器(例如登陆页面). 通过 HTML 中的 form 标签可以构造 POST 请求, 或者使用 JavaScript 的 ajax 也可以构造 POST 请求

我们登录gitte后进行抓包

POST https://gitee.com/graphql HTTP/1.1Host: gitee.comConnection: keep-aliveContent-Length: 183sec-ch-ua: "Microsoft Edge";v="111", "Not(A:Brand";v="8", "Chromium";v="111"content-type: application/jsonbaggage: sentry-environment=beta,sentry-release=v0.9.3-community,sentry-transaction=%2Fdashboard,sentry-public_key=e16c11f0b46847e9a344ce684682dde4,sentry-trace_id=37ba847cb7e74816a95cfeec2a0961a1,sentry-sample_rate=1sec-ch-ua-mobile: ?0User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.41sentry-trace: 37ba847cb7e74816a95cfeec2a0961a1-8f4825026b69e6c5-1sec-ch-ua-platform: "Windows"Accept: */*Origin: https://gitee.comSec-Fetch-Site: same-originSec-Fetch-Mode: corsSec-Fetch-Dest: emptyReferer: https://gitee.com/dashboardAccept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6Cookie: user_locale=zh-CN; oschina_new_user=false; remote_way=http; sensorsdata2015jssdkchannel=%7B%22prop%22%3A%7B%22_sa_channel_landing_url%22%3A%22%22%7D%7D; yp_riddler_id=d8d10cbb-f305-47fb-af54-a7cbfef0cf1d; Serve_State=true; Hm_lvt_a1170d3ff94c236dacd36a05af8385ea=1677675596; slide_id=9; Hm_lvt_24f17767262929947cc3631f99bfd274=1678159247,1678270356,1678894764,1679221522; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%22186e5ed16381e1-093faf17633d508-7452547c-1327104-186e5ed16391b1%22%2C%22first_id%22%3A%22%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%7D%2C%22%24device_id%22%3A%221793b84d3f7525-07b3e1fef02c7-52301642-1327104-1793b84d3f89f7%22%2C%22identities%22%3A%22eyIkaWRlbnRpdHlfY29va2llX2lkIjoiMTg2YmExNWVkNjQ1ZTMtMGE1YmUxZjBiMDZkMDA4LTc0NTI1NDc2LTEzMjcxMDQtMTg2YmExNWVkNjUxNTAifQ%3D%3D%22%2C%22history_login_id%22%3A%7B%22name%22%3A%22%22%2C%22value%22%3A%22%22%7D%7D; csrf_token=wTR5jnS6NgxYG0E9vl4C%2BlB%2FqSNr9ZbLYI9TWpAiK%2B3giPoG8FWMXJSyG1ef%2FUsInsZoxjVNwwAZSNSZveL8yQ%3D%3D; user_return_to_0=%2Fdashboard; tz=Asia%2FShanghai; Hm_lpvt_24f17767262929947cc3631f99bfd274=1679221572; gitee_user=true; gitee-session-n=YzBNTGNnYkJ5Z0toa0dGajdPUGtEMmgrUzhnU0ZQQW9IRzYyYmoxUDFaQkFhc0thZVpsN0xMZjdhT1lXL2lFamduVmdFMzQ4SFBObm1Kb01qVVBIMnZDY251eUFpOW5mcWNoS2pva3N1bzJRdEtBdGc1ek5NbzhnbzdWV3dPVlpxdDdkYk1XZ3JUYktJUkQ0R2l5ckZLeU1iK0t4ZEJnei90VENTdVR6TlBxdTVIWUFBRGNRY3ZEYWswQVV6YjJKQStXUmdRbkZuWmZidlpLSndjbTNIWmx4OUNhYVBRZ290dGZtOWRLeTh1cmNzTXR1d2IyQVVJM3g2eE93aFBKMTdzN2pmSlh2NWRoaGxWZmlxME9BUjBTVE1rTzdlV1diYnRYUDhvY29vQTdRTUtIc1VYUzRxdU9QRWN0QVRUT09OSzQvb2tEbTVaVjBqRktBZU40SkhyR25Nb011SkkwYmt2QVNGblYwZ1k5VnQ1d1JFTm5ESmc3Tmg4bUFxMVN6dTVuZHRXeHBmMHZ1bVFLeFpGUHpsMlVucnhpZS9pcU8rYi9UTTRwOHI2VTk2RUxNTEx5bkdVN2VaWDlsWmp5LzlnNmozVDRsUlNvY1dqNkpKQnFBK05iMk9nLzZid01PcFlKb2dtVURqMFcxbGl6dm5CUng0MUIrYm9lVjJsdnRHUnhoVUlId1AwQ2JZVDh0K2VRVUNQNm9QVXZEbEJPUkRZVXV0Rm5WVFljPS0tdE1TZTJXTVFyZTQ5MXRkcFFWUkoxdz09--41f366131ccbf096e3466549fca18a1d27fae4e0{"query":"\nquery unreadCount {\ncurrent_user {\nunread_count {\ninfos\nmessages\nreferer\ntotal\n}\n}\n}\n","operationName":"unreadCount"}

POST 请求的特点

首行的第一部分为 POST

URL 的 query string 一般为空 (也可以不为空)

header 部分有若干个键值对结构.

body 部分一般不为空. body 内的数据格式通过 header 中的 Content-Type 指定. body 的长度由 header 中的 Content-Length 指定

经典面试题:POST和GET之间的典型区别

1.GET可以给服务器传递一些信息,传递的信息一般都放在query string中.POST传递信息是在body中

2.语义上的差别:GET请求一般用于从服务器获取数据,POST一般用于向服务器提交数据,比如上述访问页面就是向服务器获取信息,登录则是向服务器提交信息

3.GET通常会被设计成幂等的,POST不要求幂等(如果多次请求得到的结果一样, 就视为请求是幂等的,也即相同的输入,得到的结果是确定的)

4.GET 可以被缓存, POST 不能被缓存. (这一点也是承接幂等性)

补充:

GET和POST没有本质的区别,POST也完全可以设置成幂等的,GET用来提交数据,POST也可以获取数据

关于幂等性: 标准建议 GET 实现为幂等的. 实际开发中 GET 也不必完全遵守这个规则(主流网 站都有 "猜你喜欢" 功能, 会根据用户的历史行为实时更新现有的结果

POST与GET谁更安全的问题:

有的说法:如果使用GET进行登录请求,用户名密码通过query string可以看到,因此POST更安全.但是安全指的是如果数据被窃取,敏感信息不会泄露,就是安全的,安全的核心要素是加密,就算使用POST,抓包后也能获取http的详细信息,如果信息加密了,抓包后也不能获取原始信息

关于传输数据量: 有的资料上说 "GET 传输的数据量小, POST 传输数据量大". 这个是不科学 的, 标准没有规定GET的URL的长度, 也没有规定POST的body的长度. 传输数据量多少, 取决于不同浏览器和不同服务器之间的实现区别

关于传输数据类型: 有的资料上说GET只能传输文本数据,POST可以传输二进制数据,这个也是不科学的. GET的 query string 虽然无法直接传输二进制数据, 但是可以针对二进制数据 进行 url encode

其它方法

PUT 与 POST 相似,只是具有幂等特性,一般用于更新

DELETE 删除服务器指定资源

OPTIONS 返回服务器所支持的请求方法

HEAD 类似于GET,只不过响应体不返回,只返回响应头

TRACE 回显服务器端收到的请求,测试的时候会用到这个

CONNECT 预留,暂无使用

这些方法的 HTTP 请求可以使用 ajax 来构造或者使用第三方工具(postman等)

认识请求 "报头" (header)

header 的整体的格式也是 "键值对" 结构,每个键值对占一行.

键和值之间使用分号分割. 报头的种类有很多, 此处仅介绍几个常见的

我们登录gitte网站,然后从抓包,观察结果.

Host

表示服务器主机的地址和端口,这里的端口是

Host: nav-edge.smartscreen.microsoft.com

Content-Length

表示 body 中的数据长度

Content-Length: 1544

Content-Type

表示请求的 body 中的数据格式

可取的值是非常多的:

text/html

text/css

image/png

image/jpg

application/javascript

application/json

Content-Type: application/json; charset=utf-8

这里标识数据是json(一种数据格式)格式,使用的字符集是utf8

body 格式形如:

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

还有几种常见选项:

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

title=test&content=hello

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

Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA------WebKitFormBoundaryrGKCBY7qhFd3TrwAContent-Disposition: form-data; name="text"title------WebKitFormBoundaryrGKCBY7qhFd3TrwAContent-Disposition: form-data; name="file"; filename="chrome.png"Content-Type: image/pngPNG ... content of chrome.png ...------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

User-Agent

(简称 UA) 表示浏览器/操作系统的属性

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.41

Windows NT 10.0; Win64; x64 表示操作系统信息

AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.41表示浏览器信息

Referer 表示这个页面是从哪个页面跳转过来的(当前页面的来源),如果直接在浏览器中输入URL, 或者直接通过收藏夹访问页面时是没有 Referer 的

常见的用到的地方就是广告商的链接是按点击计费的,用户点击广告,此时就会跳转到对应的广告主的网站,广告主就给广告商打钱,具体被点击了多少次,需要双方共同统计,如果数据相差不大,就没有问题

http本身明文传输,很容易获取到请求的内容,也有办法篡改内容,本来是基于A网站的请求,refer被修改成另一个网站的请求了.这种现象叫做运营商劫持,利用这个漏洞,获得本应该属于A网站的利益.

由于运营商劫持太过分,于是各大网站都升级了https进行加密传输!

cookie

本质上是浏览器给网页提供的本地存储数据的机制

浏览器的代码为了保证安全性,是不被允许访问用户的本地硬盘的,但是我们有需要浏览器能在本地存储一定的数据

cookie对浏览器访问硬盘做出了明确的限制,保证了安全性,也能让浏览器在本地存储数据

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

是通过键值对区分的,键值对之间用分号分割.具体含义是程序员定义的

我们查看gitte的cookie

我们通过三个问题理解cookie

cookie是从哪来的" />

cookie里的内容不光是键值对,还会有一个过期时间,比如很多网站登陆一次后会自动记录登录状态.短期多次登录都不会重新登录.但是长时间不登陆就会重新登陆,这是因为cookie过期了,过期时间是可以设置的,相比于有金钱交易的网站,普通网站的cookie过期时间都比较长

cookie要到哪去?

cookie是要回到服务器的,一个服务器同一时刻是有很多客户端的,通过cookie来记录当前的客户端的中间状态,当客户端访问浏览器的时候,会自动把cookie的内容带入到请求中,服务器就知道客户端目前是什么状态了

认识请求 "正文" (body)

正文中的内容格式和 header 中的 Content-Type 密切相关, Content-Type描述了正文的内容,不同的 Content-Type就会有不同的正文格式. 上面也罗列了三种常见的情况.

下面可以通过抓包来观察这几种情况

1) application/x-www-form-urlencoded(上传文件时用到)

body是类似于键值对的方式组织,键值之间使用=连接,键值对之间使用&分割

2) multipart/form-data(上传文件时用到)

body中是以分割线开始,然后以分割线结束的

3) application/json(前后端交互非常常用的数据格式,我们后面也会经常用到)

最下方的正文格式就是json格式

由于http协议十分重要并且内容也很多,此处就先介绍协议格式和http请求这两个内容,后续将会介绍http响应和如何构造http请求