上一期我们聊了状态码、异常处理,以及HTTP请求和应答报文里的那些字段。这一期接着往深处走。
先从实际场景出发,把"重定向"这件事讲明白:什么是重定向,临时重定向和永久重定向差在哪,301、302这些状态码各自适合什么场合。接着回到HTTP里最常见的两个方法,GET和POST,从表单提交、参数传递、数据放在哪、长度限制到安全性,一条条对比清楚。最后请出Fiddler这个抓包工具,顺带聊聊网络代理的基本原理,通过亲眼观察HTTP请求和响应,把整个通信过程理解得更扎实。
目录
[1.1 临时重定向:从一个生活故事说起](#1.1 临时重定向:从一个生活故事说起)
[1.2 永久重定向:为什么资源需要搬家](#1.2 永久重定向:为什么资源需要搬家)
[1.3 HTTP重定向状态码及其分类](#1.3 HTTP重定向状态码及其分类)
[1.3.1 临时重定向与永久重定向的适用场景](#1.3.1 临时重定向与永久重定向的适用场景)
[1.4 深入理解临时重定向与永久重定向](#1.4 深入理解临时重定向与永久重定向)
[1.4.1 HTTP 301:永久重定向的含义与特点](#1.4.1 HTTP 301:永久重定向的含义与特点)
[1.4.2 HTTP 302:临时重定向的含义与特点](#1.4.2 HTTP 302:临时重定向的含义与特点)
[1.4.3 永久重定向的实际价值与应用场景](#1.4.3 永久重定向的实际价值与应用场景)
[2.1 利用重定向处理请求:从错误地址到目标资源](#2.1 利用重定向处理请求:从错误地址到目标资源)
[3.1 GET与POST:两种常见的HTTP请求方法](#3.1 GET与POST:两种常见的HTTP请求方法)
[3.1.1 表单提交与请求参数的传递方式](#3.1.1 表单提交与请求参数的传递方式)
[3.1.2 GET与POST的核心区别](#3.1.2 GET与POST的核心区别)
[3.1.2.1 请求语义与参数传递位置](#3.1.2.1 请求语义与参数传递位置)
[3.1.2.2 请求参数的长度限制与影响因素](#3.1.2.2 请求参数的长度限制与影响因素)
[3.1.2.3 GET与POST的安全性分析及常见误区](#3.1.2.3 GET与POST的安全性分析及常见误区)
[3.2 Fiddler抓包工具:观察真实的HTTP通信](#3.2 Fiddler抓包工具:观察真实的HTTP通信)
[3.2.1 Fiddler的工作原理:基于HTTP/HTTPS代理的请求捕获](#3.2.1 Fiddler的工作原理:基于HTTP/HTTPS代理的请求捕获)
[3.2.2 混杂模式与网络代理:Fiddler和网卡抓包的区别](#3.2.2 混杂模式与网络代理:Fiddler和网卡抓包的区别)
一、HTTP重定向详解:从生活场景理解资源跳转
我们先不急着讲那些复杂的概念,先从两个生活中比较常见的小故事说起。
1.1 临时重定向:从一个生活故事说起
假设你们学校的东门外有一家牛肉面馆,味道还不错。某天,你和朋友约好一起去吃牛肉面,结果到了东门才发现,店门口贴着一张告示:
"由于道路施工,本店临时搬迁至西门,给您带来的不便敬请谅解。"
既然东门这边暂时吃不到了,那也没办法,你和朋友只好转头去西门,最后顺利吃上了牛肉面。
一个月后,你又想吃这家牛肉面了。这时候问题来了:你会直接去西门,还是先去东门看看?
正常来说,你还是会先去东门。毕竟上次店家说的是"临时搬迁",又没说以后都不搬回来了。说不定道路已经修好了,面馆也重新开门营业了呢?
如果到了东门,发现面馆还没搬回来,那就继续按照告示上的地址去西门。
其实,这个过程就很像临时重定向。 原来的地址依然有效,只是因为某些原因,暂时需要去另一个地址。等到下次访问时,还是会先从原来的地址开始,而不是直接认定新地址就是以后的固定位置。

1.2 永久重定向:为什么资源需要搬家
好,我们接着往下讲。
又过了一个月,你刚好路过西门,想着顺便去吃碗牛肉面。结果到了店门口,发现又贴了一张新告示:
"本店已永久搬迁至东门,今后不再迁回。"
好家伙,这家面馆又搬家了!不过这次和上次不一样,店家明确说了是"永久搬迁"。既然如此,你也没多想,直接去了东门,照样吃上了心心念念的牛肉面。
又过了一个月,你突然又想吃这家牛肉面了。这时候,你还会跑去西门看看吗?
当然不会! 既然已经知道面馆永久搬到了东门,那以后想吃的时候,直接去东门就行了,没必要再去西门绕一圈。
这个过程就是永久重定向。 和临时重定向不同,永久重定向意味着原来的资源地址已经发生了永久性变化。客户端知道这个消息后,后续就可以直接访问新地址,而不必每次都从旧地址重新寻找。

1.3 HTTP重定向状态码及其分类
HTTP 的状态码有不少,上一期我们已经讲得差不多了,不过还有一类没有详细展开,那就是 3xx 重定向状态码。
| 首位 | 类别 | 含义 |
| 1xx | 信息性状态码 | 服务器收到了请求,正在处理,先给客户端递个话。 |
| 2xx | 成功状态码 | 请求被正常接收、理解并处理,事情办成了。 |
| 3xx | 重定向状态码 | 请求的资源挪了地方,客户端得再走一趟新地址。 |
| 4xx | 客户端错误状态码 | 请求本身有问题,服务器没法处理。 |
| 5xx | 服务器错误状态码 | 请求没毛病,是服务器自己出了岔子。 |
|---|
前面通过牛肉面馆搬家的故事,我们已经了解了临时重定向和永久重定向的基本概念。而在 HTTP 协议中,常见的重定向状态码主要有下面四种:
| 状态码 | 英文名称 | 中文含义 | 主要特点 |
|---|---|---|---|
| 301 | Moved Permanently | 永久重定向 | 资源永久迁移,POST可能转为GET |
| 302 | Found | 临时重定向 | 资源临时迁移,POST可能转为GET |
| 307 | Temporary Redirect | 临时重定向 | 保留原来的请求方法和请求体 |
| 308 | Permanent Redirect | 永久重定向 | 保留原来的请求方法和请求体 |
乍一看,这四种状态码好像没什么区别,无非就是临时和永久的不同。但实际上,它们之间还有一个很关键的区别,那就是重定向之后,请求方法会不会发生变化。
至于为什么会有这样的区别,我们接着往下看。
1.3.1 临时重定向与永久重定向的适用场景
从上面这张表格中,我们不难看出,重定向主要分为临时重定向和永久重定向。那么问题来了,这两种重定向在实际开发中,分别适合用来做什么呢?
-
临时重定向: 它并不意味着原来的资源地址永久失效,只是暂时让客户端去另一个地址访问。所以,临时重定向比较适合用来处理登录跳转、临时页面跳转等场景。比如,用户访问某个需要登录的页面时,服务器发现用户还没有登录,就可以先把用户重定向到登录页面。
-
永久重定向: 这个就比较好理解了。如果网站更换了域名,或者某个资源的URL发生了永久性变化,就可以使用永久重定向。这样一来,即使用户访问的是旧地址,也能够被引导到新的地址,而不至于找不到原来的资源。
说白了,临时重定向强调的是"暂时换个地方",永久重定向强调的则是"以后就搬到这里了"。 至于具体使用哪一种,还得看实际的业务需求。
好了,前面我们一直在用比较通俗的方式理解重定向。现在,是时候把专业的概念搬出来了。
1.4 深入理解临时重定向与永久重定向
前面我们通过几个生活中的例子,已经对临时重定向和永久重定向有了大致的了解。不过,光知道它们的区别还不够,我们还得从 HTTP 协议的角度,看看重定向到底是怎么实现的。
其实,不管是301(永久重定向) ,还是302(临时重定向),它们在实现重定向时,通常都离不开一个重要的HTTP响应头字段------Location。
说到这里,大家应该还有点印象。上一篇我们零零总总聊过不少HTTP报头字段,而Location就是其中之一。至于其他常见的报头字段,别着急,后面我们还会统一整理一下。
现在,我们先来看看Location在重定向过程中究竟起到了什么作用。
1.4.1 HTTP 301:永久重定向的含义与特点
当服务器返回 HTTP301状态码时,就意味着客户端请求的资源已经被永久迁移到了新的位置。
可问题来了,服务器光告诉浏览器"资源搬家了"肯定不够吧?总得告诉人家搬到哪里去了,不然浏览器也不知道接下来该访问哪个地址。
这时候,Location响应头就派上用场了。
服务器可以在HTTP响应中添加一个Location字段,用来指定资源迁移后的新地址。浏览器收到响应后,如果支持并允许自动重定向,就可以根据这个字段提供的URL,重新向新地址发起请求。
比如,服务器可能返回下面这样的HTTP响应:
bash
HTTP/1.1 301 Moved Permanently
Location: https://www.new-url.com
Content-Length: 0
这里我们重点关注两个地方:
-
**301 Moved Permanently:**告诉浏览器,当前请求的资源已经永久搬迁,不再使用原来的地址。
-
**Location: https://www.new-url.com:**告诉浏览器,资源现在搬到了哪里,后续可以通过这个新地址进行访问。
这样一来,浏览器就知道该往哪里跳转了。
而且,由于301表示永久重定向,浏览器还可能缓存这次重定向结果。以后再次访问旧地址时,就有机会直接跳转到新地址,不需要每次都重新向旧服务器发送请求。
**说白了,301负责告诉浏览器"资源已经永久搬家",而Location则负责告诉浏览器"新家在哪里"。**两者配合起来,就能完成一次永久重定向。
1.4.2 HTTP 302:临时重定向的含义与特点
当服务器返回HTTP 302状态码时,表示客户端请求的资源暂时被移动到了另一个位置。
和301一样,服务器也需要告诉浏览器资源的新地址,所以通常也会在HTTP响应中添加一个Location字段。
浏览器收到302响应后,就可以根据Location指定的URL,临时向新地址发起请求。不过,这里有一点需要注意:302只是临时重定向,并不意味着原来的URL已经永久失效。
也就是说,浏览器这次虽然跳转到了新地址,但下次访问这个资源时,通常还是会从原来的URL发起请求,而不是直接认定新地址就是以后的固定位置。
比如,服务器可能返回下面这样的HTTP响应:
HTTP/1.1 302 Found
Location: https://www.new-url.com
Content-Length: 0
这里同样有两个地方值得关注:
-
**302 Found:**告诉浏览器,当前请求的资源暂时需要从另一个地址获取,并不代表原来的地址已经永久失效。
-
**Location: https://www.new-url.com:**告诉浏览器这次应该跳转到哪里,让浏览器能够继续访问对应的资源。
另外,302通常不会像301那样,被浏览器当作永久迁移来处理。不过,这并不代表302绝对不能被缓存。如果服务器明确设置了相应的缓存策略,302响应同样可以被缓存。
说白了,301和302都是在告诉浏览器"资源搬家了",只不过一个是永久搬迁,另一个只是临时换个地方。
到这里,我们也就能看出Location的作用了。无论是301还是302,要让浏览器知道重定向的目标地址,通常都需要依靠Location响应头字段。
它是HTTP协议中一个标准的响应头字段,用来告诉客户端应该向哪个新的URL发起请求。服务器返回重定向状态码,浏览器再根据Location提供的地址完成跳转,整个重定向过程也就串起来了。
不过,讲了这么多,可能还有人会觉得:临时重定向倒是好理解,可这个永久重定向,到底"永久"在哪里呢?
光看概念确实有点抽象。没关系,我们再来看一个具体的例子,你就明白了。
1.4.3 永久重定向的实际价值与应用场景
前面我们讲了临时重定向和永久重定向的区别,但对于普通用户来说,这两种重定向在使用体验上,其实并没有太明显的区别。 毕竟不管是301还是302,浏览器都可以自动跳转到新的地址,用户照样能够访问到对应的页面。
可对于搜索引擎来说,这两者的意义就不一样了。
大家平时应该都用过搜索引擎吧?比如,你在搜索框中输入"腾讯",搜索引擎就会根据自己已经收录的网站信息,结合网页标题、网址、内容摘要等信息,整理出对应的搜索结果。

那这些信息是从哪里来的呢?
其实,搜索引擎会通过爬虫程序不断抓取互联网上的网页,并将获取到的信息进行分析、整理和索引。这样一来,当用户搜索某个关键词时,搜索引擎就能从索引中找到相关内容,再展示出来。
但是,这里就有一个问题了:如果某家公司突然更换了网站域名,那搜索引擎之前保存的旧网址该怎么办?
假设某个网站原本使用的是www.old-url.com,后来因为业务调整,决定永久迁移到www.new-url.com。
如果服务器没有正确处理旧网址,搜索引擎再次访问时,就可能发现原来的网页已经不存在了。这样一来,不仅用户可能无法通过旧链接正常访问,搜索引擎也需要重新判断新旧网址之间的关系。
这个时候,301永久重定向的价值就体现出来了。
当搜索引擎爬虫访问旧网址时,服务器返回301状态码,并通过Location告诉它新的网址。搜索引擎收到这个响应后,就知道:哦,原来这个网站不是消失了,而是永久搬到了另一个地方。
这样一来,搜索引擎就可以把这次重定向作为网站永久迁移的重要信号,在后续抓取和索引更新的过程中,逐步将搜索结果中的旧网址替换成新网址,同时帮助原有的链接信号向新地址转移。
不过,这个过程并不是瞬间完成的,也不是说没有 301,搜索引擎就一定找不到新网站。只是有了301,搜索引擎就能更明确地理解网站的迁移关系,减少不必要的判断。
而如果使用的是302,搜索引擎通常会认为网站只是临时换了位置,因此更倾向于继续保留原来的网址。说到这里,大家应该就明白了。
永久重定向的一个重要价值,就是在网站更换域名或URL时,不仅让用户能够通过旧地址访问新网站,还能帮助搜索引擎识别资源的永久迁移关系,逐步更新索引,尽可能保留原有的搜索表现。
所以,301可不只是简单地让浏览器跳转一下,它在网站迁移和搜索引擎优化(SEO)中,同样发挥着非常重要的作用。
二、HTTP重定向的工作原理与实际应用
前面我们已经搞清楚了什么是重定向,也知道了临时重定向和永久重定向之间的区别。

不过,重定向到底是怎么实现的呢?浏览器又是怎么知道自己应该跳转到哪个地址的?
其实,整个过程并不复杂,我们按照浏览器和服务器之间的交互流程来看一看。
-
浏览器向服务器发送请求。 比如,用户在浏览器中输入一个URL,浏览器就会根据这个地址,向对应的服务器发起HTTP请求。
-
服务器收到请求后,返回重定向响应。 这个响应中会包含HTTP状态码(比如301、302),以及一个非常重要的响应头字段,Location,用于告诉浏览器资源的新地址。
这里顺便提一句,HTTP响应通常由状态行、响应头、空行和可选的响应体组成。对于重定向响应来说,响应体可以为空,毕竟服务器主要是想告诉浏览器:"你要找的资源不在这里,去另一个地址看看。"
-
浏览器解析服务器返回的HTTP响应。 当浏览器发现状态码是301、302等重定向状态码时,就会进一步读取Location字段,从中获取需要跳转的新URL。
-
浏览器根据新的URL,再次发送HTTP请求。 如果浏览器允许自动重定向,就会向
Location指定的地址发起第二次请求。至于请求方法和请求体是否保持不变,还得看具体使用的是哪一种重定向状态码。
举个例子,假设浏览器原本访问的是:http://www.example.com/old
结果服务器返回了下面这个响应:
HTTP/1.1 302 Found
Location: http://www.example.com/new
Content-Length: 0
浏览器一看,哦,原来这个资源临时换地方了,新地址是/new。
于是,它就会向新地址重新发起请求:
bash
GET /new HTTP/1.1
Host: www.example.com
如果新地址对应的服务器正常返回资源,比如返回200 OK,浏览器就可以继续处理并展示页面内容了。
所以,重定向并不是服务器直接把浏览器"推"到了另一个地址,而是服务器通过状态码和Location告诉浏览器应该去哪里,再由浏览器主动发起新的请求。
整个过程看起来像是一次页面跳转,但实际上,浏览器已经完成了至少两次HTTP请求与响应交互。
2.1 利用重定向处理请求:从错误地址到目标资源
这里我们换一种新的设计思路。
以前服务器遇到错误请求时,需要自己构建对应的错误页面,再将页面内容返回给浏览器。
但现在有了重定向,我们就可以直接返回一个302状态码,让浏览器重新请求服务器上已经准备好的404.html页面。
对应我们的C++代码就是:
cpp
#include <filesystem>
#include <string>
bool HttpResponse::HandleRequest(const std::string& url)
{
// 根据请求的 URL 拼接本地资源路径
std::string filePath = "./wwwroot" + url;
// 判断客户端请求的资源是否存在
if (!std::filesystem::is_regular_file(filePath))
{
// 避免 404 页面不存在时发生无限重定向
if (url == "/404.html")
{
SetCode(404);
return true;
}
// 设置临时重定向状态码
SetCode(302);
// 告诉浏览器新的资源地址
SetHeader("Location",
"http://8.138.21.101:8080/404.html");
return true;
}
// 资源存在,正常处理
SetCode(200);
return true;
}
这里的HttpResponse::HandleRequest()是按照我们前面使用的SetCode()和SetHeader()接口写出的示例处理函数,实际项目中还需要接入原有的文件读取和响应发送逻辑。
当请求的资源不存在时,服务器会返回:
HTTP/1.1 302 Found
Location: http://8.137.19.140:8080/404.html
Content-Length: 0
浏览器拿到这个响应后,就会自动向Location指定的地址发起第二次请求:
GET /404.html HTTP/1.1
Host: 8.137.19.140:8080
如果服务器能够正常找到404.html,就可以返回:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
后面再跟上404.html对应的页面内容,浏览器就能够正常显示错误提示页面了。
不过需要注意,这里的200 OK表示第二次请求成功获取了错误页面,并不代表第一次请求的资源存在。实际开发中,如果希望客户端和搜索引擎正确识别资源不存在,通常还是应该直接返回404状态码。
Tips:讲点故事
(和文章内容无关,感兴趣的可以看看,不感兴趣也可以直接跳过。)
把时间拨回到上世纪90年代末、千禧年前后。那时候,智能手机还没普及,人们想上网,基本都得守在电脑前。而在那个年代,有一款软件的地位相当特殊,那就是浏览器。
毕竟,不管你是想查资料、看新闻,还是浏览网页,都绕不开它。可以说,在移动互联网还没有兴起的时候,浏览器就是互联网最重要的流量入口之一。
早期的浏览器市场,有一位响当当的霸主,叫做网景领航员(Netscape Navigator)。

不过,好景不长。微软很快也盯上了这块市场。1995年,微软推出了自己的Internet Explorer(IE)浏览器,并借助Windows操作系统庞大的用户基础,以及后续的系统捆绑和预装优势,迅速抢占市场。
你想想,当用户打开电脑,发现系统已经自带浏览器了,那还有多少人愿意专门去下载另一款呢?
就这样,IE的市场份额一路攀升,曾经风光无限的网景领航员逐渐败下阵来,最终退出了主流浏览器市场。
但故事到这里还没结束。浏览器这块蛋糕实在太诱人了!谁掌握了浏览器,谁就有机会掌握大量的用户流量,还能通过默认搜索引擎等方式获得商业收益。面对这么大的市场,其他互联网公司自然也想进来分一杯羹。
谷歌当然也不例外。2008年,谷歌正式推出了Chrome浏览器 ,同时开放了它背后的开源项目Chromium。凭借速度、稳定性以及不断改进的用户体验,Chrome逐渐在浏览器市场站稳了脚跟,并成长为主流浏览器之一。
不过,浏览器厂商之间的竞争,可不只是抢用户那么简单。
浏览器离商业利益太近了,各家公司都想掌握更多的话语权。 早期的浏览器厂商经常各搞各的技术,有些网页在这个浏览器上能正常显示,换一个浏览器就可能出现排版错乱、功能失效等问题。
这就很头疼了。
对于开发者来说,总不能为了让一个网页正常运行,还得针对不同的浏览器写好几套代码吧?
一个行业想要长期发展,光靠各家公司闷头搞技术肯定不行,还得有一套大家共同遵守的标准。
其实,万维网联盟(W3C)早在1994年就已经成立,并开始推动Web标准化。只是标准有了,不代表所有浏览器都会老老实实遵守。各家厂商为了竞争,依然会加入自己的专有功能,浏览器之间的兼容性问题也就一直存在。
后来,随着W3C、WHATWG等标准化组织持续推动Web技术规范,加上浏览器厂商不断改进标准支持,情况才慢慢好转。
而Chrome及其背后的Chromium项目逐渐壮大,也对浏览器技术生态产生了很大的影响。
当然,这并不意味着浏览器之间从此就没有兼容性问题了,只是相比早期那种各自为政的局面,如今的Web开发已经规范了许多。
回头再看这段历史,其实还挺有意思的。
从网景领航员到IE,再到后来的Chrome,浏览器之间的竞争从来没有真正停止过。只不过,随着技术不断发展,大家也越来越清楚:竞争归竞争,统一的技术标准同样重要。
三、HTTP常见请求方法:GET与POST详解
前两篇文章中,我们其实已经接触过HTTP的请求方法了,比如最常见的GET和POST。不过,当时主要还是围绕HTTP请求报文展开,并没有把这些方法单独拿出来详细讲解。
那么问题来了,HTTP请求方法到底有哪些?它们又分别是用来干什么的呢?
其实,HTTP协议定义了多种请求方法,每种方法都有自己的用途。说得简单一点,就是客户端在向服务器发送请求时,需要告诉服务器:我这次过来,到底是想获取资源、提交数据,还是对资源进行其他操作?
我们先通过一张表格,简单认识一下这些请求方法。
| 请求方法 | 作用说明 |
|---|---|
| GET | 获取服务器上的资源 |
| POST | 向服务器提交数据 |
| PUT | 创建或整体替换目标资源 |
| HEAD | 获取响应头,不返回响应体 |
| DELETE | 请求删除指定资源 |
| OPTIONS | 查询目标资源支持的通信选项 |
| TRACE | 用于请求回环测试,辅助诊断 |
| CONNECT | 建立网络隧道,常用于代理服务器 |
| PATCH | 对已有资源进行局部修改 |
看到这里,有些方法大家应该已经很熟悉了,比如GET和POST,平时浏览网页、登录账号、提交表单,都可能用到它们。
但像HEAD、OPTIONS、TRACE这些方法,可能就没那么熟悉了。
不过,不熟悉也没关系。我们先知道HTTP有这些请求方法,至于它们具体怎么使用、有什么区别,接下来再慢慢展开。
3.1 GET与POST:两种常见的HTTP请求方法
在HTTP协议中,GET和POST可以说是我们最常接触的两种请求方法了。
通常情况下,GET主要用于向服务器获取资源 ,比如图片、视频、音频、网页等。而POST则更多用于向服务器提交数据,比如用户登录、表单提交、文件上传等。
不过,这里有一个很容易让人产生误解的地方:GET就只能获取资源,POST就只能上传数据吗?
其实并不是。在实际开发中,GET同样可以携带数据,比如通过URL中的查询参数,将搜索关键词、用户ID等信息传递给服务器。服务器收到这些参数后,再根据请求返回对应的资源。
而POST也不只是用来上传文件,它还可以提交表单、创建资源,或者让服务器执行某些数据处理操作。
所以,GET和POST的区别,并不是简单地看有没有向服务器传递数据,而是要看请求的目的,以及它们在HTTP协议中各自定义的语义。
至于这两种方法具体有什么区别,我们接着往下看。
3.1.1 表单提交与请求参数的传递方式
在网页前端开发中,比如我们常见的登录页面(Login),用户往往需要填写一些信息,再通过表单提交给服务器。
这里有个小细节:如果HTML表单没有指定method属性,那么默认使用的就是GET方法。
假设用户打开一个登录页面,输入用户名和密码,点击登录按钮。这时候,浏览器就需要把用户填写的信息发送给后台服务器,让服务器进行验证。

那么,GET和POST分别是怎么传递这些参数的呢?
-
GET提交参数: GET通常通过URL中的查询字符串传递参数。具体来说,就是在URL后面加上一个问号(?),再把需要提交的参数拼接上去。如果有多个参数,就使用&进行分隔。
比如下面这个地址:http://8.x.19.x:8080/Login?username=lisi&password=54321

-
POST提交参数: POST则通常把需要提交的数据放在HTTP请求的正文(Request Body)中,而不是直接拼接到URL后面。
比如,我们可以在请求正文中携带下面这些数据:username=lisi&password=54321
服务器收到请求后,再根据对应的数据格式,从请求正文中解析出用户名和密码,完成后续的登录验证。
看到这里,大家应该就能发现两者的区别了。
GET通常通过URL中的查询参数传递数据,而POST通常通过请求正文传递数据。
不过,这里还得提醒一下:实际开发中,登录这类涉及密码的操作,不建议使用GET提交。 因为GET的查询参数会直接出现在URL中,可能被浏览器历史记录、服务器日志等保存下来。
POST虽然可以避免把密码直接放在URL中,但也不代表数据天然就是安全的。真正涉及用户名、密码等敏感信息时,还需要配合HTTPS来保护传输过程。
说到这里,我们再稍微延伸一下。
在实际开发中,我们经常会在后台提供各种服务接口,比如用户注册、登录、查询用户信息等。客户端只需要按照约定的URL、请求方法和参数格式发送HTTP请求,就可以调用这些服务。
而在Web API的设计中,还有一种非常常见的架构风格,叫做REST(Representational State Transfer) 。遵循REST架构约束设计的接口,通常被称为RESTful API。

它强调以资源为中心,合理利用GET、POST、PUT、DELETE等HTTP方法来表达不同的操作。
当然,并不是说后台提供了HTTP接口,就一定属于RESTful。具体还得看接口是否符合 REST 的设计约束。
3.1.2 GET与POST的核心区别
前面我们已经了解了GET和POST的基本用法,也知道了它们是如何向服务器传递参数的。不过,这两种请求方法的区别,可不只是参数放在哪里这么简单。
下面我们从几个比较常见的角度,来看看它们到底有什么不同。
3.1.2.1 请求语义与参数传递位置

-
GET方式: 主要用于向服务器获取资源,比如网页、图片、视频等。如果需要传递参数,通常会将参数拼接到URL后面,通过查询字符串的方式发送给服务器。
-
POST方式: 主要用于向服务器提交需要处理的数据,比如登录信息、表单数据、上传文件等。这些数据通常放在HTTP请求正文(Body)中进行传输。
说白了,GET通常把参数放在URL中,而POST则通常把数据放在请求正文中。 不过,这只是两者常见的传参方式,并不是它们在HTTP协议中的全部区别。
3.1.2.2 请求参数的长度限制与影响因素
-
GET 提交参数: 由于参数通常拼接在URL后面,所以不建议传递过长的数据。虽然HTTP协议没有为URL规定一个统一的最大长度,但浏览器、服务器以及中间代理都可能对URL长度进行限制。
-
POST正文传参: POST通常通过请求正文传递数据,不受URL长度的直接限制。因此,它更适合提交表单内容、上传文件等数据量较大的场景。
不过,POST也不是想传多少数据就能传多少。 服务器可能会对请求正文的大小进行限制,实际能够传输多少数据,还得看服务器的配置以及应用程序的处理能力。
3.1.2.3 GET与POST的安全性分析及常见误区
-
GET方式: 当参数通过URL传递时,这些参数会直接出现在浏览器的地址栏中。虽然看起来很直观,但也容易被浏览器历史记录、服务器日志等保存下来。如果传递的是密码之类的敏感信息,就可能带来安全隐患。
-
POST方式: POST通常把数据放在请求正文中,不会像URL查询参数那样直接显示在地址栏里。从这个角度来看,确实比GET更隐蔽一些。
但是,这里有一个非常容易被误解的地方:POST并不意味着数据就是安全的!
为什么这么说呢?因为GET和POST说到底都只是HTTP的请求方法,它们本身并不负责加密数据。如果使用的是普通HTTP,那么无论参数放在URL 中,还是放在请求正文中,数据都可能在传输过程中被窃听,甚至被篡改。
所以,真正需要保护数据传输安全时,关键不是选择GET还是POST,而是使用HTTPS协议。
HTTPS会通过TLS对传输中的HTTP数据进行加密和完整性保护,让网络中间的第三方难以直接读取或篡改请求内容。
当然,HTTPS保护的是传输过程,并不代表数据到了服务器之后就绝对安全。像密码这类敏感信息,仍然需要做好日志保护、安全存储等工作。
GET和POST各有各的用途,不能简单地认为GET不安全、POST就安全。具体使用哪一种方法,还是要结合请求的语义、数据量以及实际业务场景来判断。
3.2 Fiddler抓包工具:观察真实的HTTP通信
3.2.1 Fiddler的工作原理:基于HTTP/HTTPS代理的请求捕获
前面我们讲GET和POST的时候,一直在说请求参数、请求正文这些东西。那有没有一种工具,能够让我们直接看到浏览器和服务器之间传递的HTTP报文呢?
当然有!这里就给大家介绍一款比较常见的抓包工具------Fiddler。
Fiddler的工作原理其实并不复杂,它本质上就是一个HTTP/HTTPS代理工具。

正常情况下,浏览器向服务器发送请求,服务器处理完后再把响应返回给浏览器,双方直接进行通信。但如果我们启用了Fiddler,并且浏览器的网络流量经过它的代理,那么整个交互过程就有点不一样了。
原本浏览器和服务器之间的通信,现在相当于多了一个"中间人",而这个中间人就是Fiddler。
假设我们在浏览器的登录页面中输入用户名和密码,点击登录按钮,这时候整个请求过程大致可以分为以下几个步骤:
-
浏览器构建HTTP请求: 当用户点击登录按钮后,浏览器会根据表单的提交方式,将用户名、密码等数据组织成对应的HTTP请求报文。也就是说,Fiddler接收到的请求,已经是浏览器按照HTTP协议构建好的请求。
-
Fiddler接收并转发请求: 如果浏览器配置了Fiddler代理,那么请求就会先发送给Fiddler。Fiddler可以记录并解析请求内容,再将请求转发给真正的目标服务器。这里要注意,转发并不意味着网络数据一定原封不动,代理可能会重新建立连接,必要时还可以修改请求内容。
-
服务器处理请求并返回响应: 目标服务器收到请求后,会按照正常的业务逻辑进行处理,比如验证用户名和密码是否正确,再将处理结果作为HTTP响应返回。
-
Fiddler接收并转发响应: 服务器返回的响应同样会先经过Fiddler。Fiddler可以记录响应状态码、响应头以及响应正文等信息,再把响应转发给浏览器。
这样一来,浏览器和服务器之间的请求、响应,就都可以通过 Fiddler 进行观察和分析了。
整个通信过程可以简单理解为:
浏览器 → Fiddler → 目标服务器 → Fiddler → 浏览器
不过,看到这里,可能有人会问了:
既然Fiddler可以抓取HTTP报文,那是不是连用户提交的账号密码也能直接看到呢?
对于普通的HTTP请求,如果账号密码以明文形式放在URL或请求正文中,那么在经过Fiddler代理时,确实可以被查看到。

但如果使用的是HTTPS,情况就不一样了。
因为HTTPS会使用TLS对传输的数据进行加密,Fiddler默认并不能直接读取其中的明文内容。只有在客户端明确配置并信任 Fiddler 的根证书,同时启用HTTPS解密功能等条件下,Fiddler才能够对相应的HTTPS流量进行解密和分析。
这也正好说明了我们前面提到的一个问题:
GET和POST本身都不负责加密。真正保护数据传输安全的,是HTTPS所使用的TLS加密机制。
当然,Fiddler不只是用来查看请求参数的。平时开发Web服务时,我们还可以利用它检查HTTP状态码、分析请求头和响应头、排查接口异常等问题。
对于我们学习HTTP协议来说,这种能够直接观察请求与响应报文的工具,还是相当实用的。
3.2.2 混杂模式与网络代理:Fiddler和网卡抓包的区别
前面我们已经了解了Fiddler的基本工作原理,不过这里还有一个很容易搞混的地方,那就是网卡的混杂模式(Promiscuous Mode)和 HTTP/HTTPS 网络代理(Proxy)之间的区别。
有些资料可能会提到这样一种说法:
"发送到局域网中的数据,会被局域网内的所有主机接收到。只要打开抓包工具,就能监听到局域网中的所有网络请求。"
这种说法其实并不严谨,而且还容易把两种不同的抓包机制混为一谈。
像Wireshark这样的抓包工具,主要是通过操作系统提供的数据包捕获机制,在网络接口上捕获数据包。它可以使用网卡的混杂模式(Promiscuous Mode),让网卡接收更多经过该网络接口的数据帧,而不只是接收目标MAC地址为自己的单播帧。
不过,这并不意味着开启混杂模式,就能随意抓取整个局域网中所有设备的数据。
为什么呢?因为现代局域网大多使用交换机进行数据转发。交换机通常只会将单播数据帧转发到对应的端口,而不是把所有数据都广播给每一台主机。
所以,混杂模式只能让网卡尽可能接收已经到达本机网络接口的数据,并不能让原本不会经过本机的数据凭空出现。
而我们这里介绍的Fiddler,工作机制就完全不同了。
Fiddler主要依靠HTTP/HTTPS 代理(Proxy)来获取和分析网络请求,而不是通过网卡混杂模式直接监听整个局域网。
它的工作过程大致可以分为以下几个步骤:
-
代理设置: 以经典版Fiddler Classic为例,启用流量捕获后,通常会将系统代理配置为127.0.0.1:8888。这里的127.0.0.1表示本机回环地址,而8888则是Fiddler默认使用的代理监听端口。这样一来,使用系统代理设置的浏览器,就可以把HTTP请求交给Fiddler处理。
-
请求转发: 当浏览器发现系统配置了代理,就会按照代理规则,将原本需要直接发送给目标服务器的请求,先交给 Fiddler。注意,这里并不是前面讲的HTTP 301、302重定向,而是浏览器主动按照代理配置改变了请求的发送路径。
-
中间人转发: Fiddler收到请求后,会作为代理与目标服务器进行通信。服务器处理完请求,再将响应返回给 Fiddler,最后由Fiddler将响应转交给浏览器。在这个过程中,Fiddler 可以记录和分析HTTP报文,也可以根据配置修改请求或响应内容。
这里还得补充一句:如果访问的是HTTPS网站,Fiddler想要查看加密后的HTTP内容,就需要启用HTTPS解密功能,并让客户端信任对应的解密证书。否则,它通常只能观察到代理连接等有限信息,而无法直接读取加密的请求正文。
说到这里,两者的区别应该就比较清楚了。
Wireshark更偏向于从网络接口捕获数据包,而Fiddler则更偏向于通过代理接收、转发和分析HTTP请求。
前者适合分析TCP、UDP、IP等不同层次的网络通信,后者则更适合我们平时调试 HTTP 接口、查看请求参数以及分析服务器响应。
当然,Wireshark也能够解析HTTP流量,只不过它和Fiddler获取流量的方式并不相同。
说白了,一个主要是在网络接口上"抓经过的数据",另一个则是让请求主动"从自己这里经过"。理解了这个区别,也就不容易把混杂模式和代理抓包搞混了。
好了,到这里,本篇关于HTTP协议的内容就讲得差不多了。
这一篇我们主要围绕HTTP重定向、常见请求方法以及抓包工具Fiddler展开。从最开始牛肉面馆搬家的故事,到301、302等重定向状态码的区别,再到浏览器如何通过Location发起二次请求,相信大家对重定向的工作原理已经有了更清晰的认识。
后面我们又聊到了GET和POST,弄清楚了它们在参数传递、数据长度以及安全性方面的区别。顺便还认识了Fiddler,知道了如何借助抓包工具,观察浏览器和服务器之间真实的HTTP请求与响应。
其实,HTTP协议中的很多知识点,单独看可能觉得挺抽象,但只要把它们放到实际的网络通信过程中,再结合一些生活中的例子去理解,就会发现并没有想象中那么复杂。
学协议,光记住几个状态码、几个请求方法还不够,更重要的是弄明白:客户端为什么要这样发送请求,服务器又为什么要这样返回响应。
毕竟,我们学习HTTP,最终还是要把这些知识运用到自己的网络程序和服务器开发中。
好了,本篇文章就先聊到这里。如果文章中有什么理解不到位或者讲错的地方,也欢迎大家在评论区指出,一起交流、一起进步!
我们下篇文章再见!