📚 本文收录于「流浪」的系列专栏
| 🐧Linux系统 | ⚙️C++ |
| 📊数据结构与算法 | 🐍Python |
| 🔗LangChain & LangGraph | 🗄️MySQL 数据库 |
| 🌿Git 工具 | 🌐计算机网络 |
| 🤖LLM | 💯大厂面试、八股 |
| 📚学习筑基专栏 |
🏠 博客主页:流浪 | 📝 原创首发于 CSDN
前言:《计算机网络篇10》把请求那一半收齐了:方法、URI、版本,还有一条报文怎么完整读出来。服务器收到请求后要用三位数回话,请求换地址时用 Location 指路,头部还有几个字段各管一件事,这一篇收尾响应侧。
一、状态行与状态码
1.1 状态码是服务器对一次请求的处理结论
1. 客户端靠状态码决定要不要走异常处理分支
- 客户端发请求时只知道「我要什么」,不知道服务器会怎么答:资源在不在、权限够不够、服务器自己有没有崩,这些结论得由服务器写在状态行里。
- 状态码就是三位数的处理结论,第一位定大类、后两位说细节,客户端拿到之后按类走不同分支——成功就渲染,重定向就跟随,客户端错就提示用户,服务端错就退避重试或报障。
- 这套分类顶住了协议演进:新冒出来的 4xx 码客户端不认识,也知道是「这次请求本身有问题」,处理逻辑一个字都不用改。
1.2 五类状态码按「谁的问题」划分,客户端据此决定怎么办
《计算机网络篇9》用一张表列过五类状态码和常见取值,这里按处理动作重新归类,看的是客户端拿到之后该做什么。
- 1XX 与 2XX 都属于正常推进:1XX 是过程状态(请求收到了、还在处理),2XX 是最终成功,两种都不需要异常分支。
- 3XX 是换地址:客户端读出 Location,自动再发一次请求,用户只看到页面到了。
- 4XX 是客户端的问题:请求本身错了,原样重发还是错,重试没有意义,要改的是请求——补权限、改路径、修参数。
- 5XX 是服务端的问题:请求本身没错,是服务器暂时处理不了,可以退避重试。
- 这条区分的工程价值最大:重试逻辑只看第一位,4 开头不重试、5 开头可重试,一个判断省掉大量无效请求。
- 大类不能乱用,后两位可以自定义——服务器可以造一个 499 表示客户端主动断开,客户端仍按「客户端错」处理。
状态码第一位决定客户端怎么处理,后两位的细节可以自定义,大类不可乱用。
1.3 常见的状态码
二、重定向:服务器不直接给结果,而是把请求指到新地址
2.1 重定向是服务器回一个 3XX 加一个 Location
- 有些请求服务器不想或不方便直接答:资源搬到了新域名、页面要先登录、站点正在维护,这时它不回正文,而是回一个 3XX 状态码加一个
Location头,告诉客户端「去这个地址拿」。 - 客户端收到 3XX,读出 Location,自动对新地址再发一次请求,整个过程用户只看到地址栏变了、页面出来了。
- 这是 HTTP 层的动作,浏览器和 HTTP 客户端库默认都会自动跟随(follow),不需要用户点、也不需要代码手动跳。
2.2 未登录点充值被指去登录页再回来,是重定向在起作用
1. 没登录点充值,请求被指到登录页
- 打开酷狗准备充会员,还没登录就点了充值按钮:请求发到充值页,服务器一查没有登录凭证,不返回充值页,而是回
302加一个Location: 登录页地址。 - 浏览器跟着 Location 跳到登录页,用户完成登录,这时地址栏里已经是登录页的地址。
- 登录成功后,服务器再回一个
302加Location: 充值页地址(通常带一个回跳参数),浏览器跟着跳回充值页,这次请求带着刚拿到的登录凭证,充值页正常返回。
2. 被支走又回来,拿到的还是原来要的东西
- 整个过程用户的目标没变——充会员,中间被支去登录,登录完又被送回充值页,这就是重定向的日常形态。
- 每一次「支走」都是一次 3XX 响应:响应里没有正文,只有状态行、Location 头,外加那个必须存在的空行。
- 登录跳转几乎都用临时重定向:用户下次再来,还是可能先落到充值页、再被指去登录,这条路径不能写死。
2.3 301 永久重定向与 302 临时重定向的区别
1. 302 临时重定向:这次去新地址,下次仍回老地址
- 临时重定向表示「这个地址只是暂时不能用、或暂时该去别处」,资源的正式地址还是原来那个。
- 客户端不会把这次跳转记成永久关系:下次再访问,仍然先请求老地址,由服务器重新指一次。
- 登录跳转、临时活动页、A/B 测试都用它——随时可能改回来,不能让客户端记死。
2. 301 永久重定向:老地址作废,以后直接去新地址
- 永久重定向表示资源已经搬家,原来那个地址以后不该再用。
- 客户端会记住这个映射,下次直接请求新地址、不再回老地址确认;搜索引擎也会把老地址的权重转到新地址。
- 更换域名、改版换路径用它;反过来,临时改地址却写成 301,客户端记死了错误映射,再改回来要等缓存过期,这是最常见的误用。
3. 307 和 308 与 302、301 的差别在方法保不保
- 301 和 302 在历史实现里被处理成「跟随重定向时可能把 POST 改写成 GET」,方法和请求体都会丢——对「提交订单后跳结果页」这类场景是灾难。
- 后来的标准(RFC 7231 起,现行 RFC 9110)补了两个码:307 是临时重定向、308 是永久重定向,两者都要求客户端保持原方法和请求体再发到新地址。
- 所以严格的临时重定向用 307,严格的永久重定向用 308;301/302 因为历史包袱仍在广泛使用,浏览器对它们的方法改写行为也成了默认。
2.4 重定向的响应只有状态行、Location 和空行
- 一个典型的重定向响应就三样:
- 状态行
HTTP/1.1 302 Found - 一个
Location: 新地址头 - 空行之后正文为空
- 状态行
- 客户端只看两样东西:状态码是不是 3XX、Location 指向哪里;正文为空,因为要的内容不在这次响应里。
- 请求链路完整走一遍:客户端访问老地址 → 服务器回 302 加 Location → 客户端对新地址再发一次请求 → 新地址返回 200 和正文。
301 和 308 是永久、302 和 307 是临时,真正的区别在于客户端下次还回不回老地址、跟随的时候方法和请求体保不保持。
2.5 东门西门饭店门口的告示,讲清了临时与永久的差别
告示写「临时装修,请移至西门」,下次还得回东门看一眼
- 学校东门口有一家饭店,去吃饭时发现门上贴着一张告示:「临时装修,暂停营业,请移至西门」,想吃这口饭,只能往西门再跑一趟。
- 过了一个月又想吃,可你不确定店到底开在东门还是西门,于是仍旧先去东门(老地方)看一眼,告示还贴在那儿,就再往西门走。
- 这就是临时重定向:每一次都先回老地方确认一遍,店没搬走、只是暂时不在老地方营业;登录跳转就是这类,办完事还要回到原来的目标页。
告示改成「永久搬迁至西门」,下次直接去西门
- 如果告示写的是「永久搬迁至西门」,下一次吃饭就不必回东门了,直接去西门就行——老地方的记忆被这一次告示改写掉。
- 这就是永久重定向:客户端把新地址记下来,以后直接请求新地址;换域名、换网址这类真搬家,用的就是它。
- 两张告示的差别不在「这次去哪吃」,而在「下次还回不回东门看一眼」,这正是 301 与 302 在客户端行为上的分野。
临时重定向是「去西门吃,但下次还先回东门看告示」,永久重定向是「告示说搬了,以后直接去西门」,而门口那张告示,就是服务器递过来的 3XX 响应加 Location。
三、HTTP 常见 Header
《计算机网络篇10》把Content-Length和Content-Type单独讲过,一个定正文长度、一个定正文格式;Location在重定向那一章已经出场。这一章收剩下的五个常用字段,每个都只解决一件具体的事。
3.1 Host 指定这次请求要访问哪个站点
- 一台服务器上可以挂很多个网站(虚拟主机),请求到达时靠 Host 头区分这次要哪个站点。
- HTTP/1.1 里 Host 是必填字段,缺了它服务器直接回 400——没有它,服务器不知道该把请求交给哪个站点处理。
- 本机改 hosts 文件把域名指到本地,Host 里写的仍然是目标域名,这正是本地联调能跑通的原理。
3.2 User-Agent 报客户端身份,反爬虫策略以它为第一道门槛
1. User-Agent 是客户端自己写的身份声明
- 浏览器发请求时会带一串 User-Agent,里面是浏览器类型、版本、操作系统,服务器据此返回 PC 页面或移动端页面。
- 这串内容是客户端自己写的,协议不做任何强制校验——写什么由客户端决定,服务器只能选择信或不信。
2. 反爬虫机制的基础就是校验 User-Agent
- 爬虫程序用 HTTP 库直接发请求时,User-Agent 往往是库的默认值(形如
python-requests/2.x),和真实浏览器差得明显。 - 服务器的策略据此展开:
- 维护一份黑名单,命中默认 UA 直接拒绝
- 或者反过来,只放行常见浏览器 UA,其余一律 403
- 爬虫的第一步伪装也就是把这个字段改成真实浏览器的值——双方围绕这一个字段拉锯多年,现在的反爬早已叠加了 IP 频率、行为轨迹、验证码多重校验。
3. 用 HTTP 客户端调接口时,User-Agent 写成自己的服务名
- 正常开发里调第三方接口,把 User-Agent 设成「自己的服务名 + 用途 + 联系方式」是负责任的写法:对方能识别流量来源,出问题能找到人。
- 伪装成浏览器 UA 去抓别人明确拒绝的数据,是绕过对方的技术措施,越过了技术问题本身的边界。
3.3 Referer 报这次请求从哪个页面跳过来
- Referer 记录来源页面的地址:用户从一个页面点链接跳到另一个页面,新请求会带上来源地址。
- 两个典型用途:统计流量来源(从搜索引擎来还是直接输入网址),防盗链(图片服务器校验 Referer 是否来自本站,站外直接引用一律拒绝)。
- 它同时会暴露浏览记录,浏览器支持用
Referrer-Policy控制发送策略,敏感场景可以完全不带。
3.4 Connection 控制连接用完关不关
- HTTP/1.1 默认长连接,多个请求复用一条 TCP 连接,省掉反复三次握手、四次挥手的开销。
- 想关连接就带
Connection: close,服务器处理完这次请求主动断开;反过来,HTTP/1.0 要显式写Connection: keep-alive才会复用。 - 长连接不是越长越好:闲置连接占着服务器的 fd 和内存,实际部署靠超时和最大请求数收口。
3.5 Cookie 让无状态的 HTTP 记住同一个客户端
- HTTP 本身不记人:两次请求之间服务器没有任何上下文,这是「无状态」的含义;好处是服务器不必为每个客户端保留会话状态,扩缩容容易。
- Cookie 是打在这套设计上的补丁:服务器在响应头里用
Set-Cookie下发一小段键值,浏览器保存,之后发往同域的请求自动带上Cookie头,服务器凭它认出「还是这个人」。 - 登录态就是最典型的用法:登录成功后服务器发一个会话 ID,后续请求带上它,服务器查会话表就知道是谁——Session 存在服务端,Cookie 只是它的搬运工。
Host 定站点、User-Agent 报身份、Referer 报来源、Connection 定连接寿命、Cookie 补上无状态缺的那份记忆,每个字段都在解决一个具体问题。
四、全篇总结
1. 状态码的第一位决定客户端怎么处理
- 1XX 与 2XX 是正常推进,3XX 是换地址,4XX 是请求本身有错、不该重试,5XX 是服务端故障、可以退避重试。
2. 重定向靠 3XX 加 Location 把请求指到新地址
- 一次重定向响应只有状态行、Location 和空行,客户端读完自动对新地址再发一次请求。
3. 301 和 308 永久、302 和 307 临时
- 永久会被客户端记住、以后直连新地址,临时每次都先回老地址;307 和 308 额外要求保持原方法和请求体。
4. 常见 Header 各管一件事
- Host 定站点、User-Agent 报身份并支撑反爬、Referer 报来源并支撑防盗链、Connection 定连接寿命、Cookie 补上无状态缺的记忆。
五、文末面试题
5.1 推导题(按本篇知识点)
1. 为什么 4XX 不该重试、5XX 可以重试?
答(推导):4XX 说明这次请求本身不合格——路径错了、没权限、参数格式不对,原样重发一百次还是同样的错,要改的是请求内容。5XX 说明请求没问题,是服务器暂时处理不了(过载、上游超时、维护中),稍后重发有可能成功,所以退避重试有意义。重试逻辑按状态码第一位判断,正是这个道理。
2. 永久重定向和临时重定向在客户端行为上差在哪?
答(推导):临时重定向(302/307)不改变客户端的访问习惯,下次仍先请求老地址,由服务器重新指一次;永久重定向(301/308)会被客户端记住映射,下次直接请求新地址,搜索引擎也会转移权重。两者选错的代价不对称:临时改地址写成永久,客户端会长期访问错误地址,等缓存过期才能纠正。
3. 登录跳转为什么用 302 或 307,而不用 301 或 308?
答(推导):登录跳转是临时行为——用户的正式目标地址没有搬家,只是这一次没有凭证被支去登录页,登录完还要回来。用永久重定向会让客户端把「目标地址 = 登录页」记死,下次直接去登录页,反而拿不到原本要的资源。提交表单后跳转的场景还要保方法和请求体,所以严格用 307。
5.2 真题
1. HTTP 常用的状态码?
答(推导 · 已对照解析,转述):按五类记:1XX 信息性(100 继续),2XX 成功(200 正常、201 创建成功、204 无正文、206 部分内容),3XX 重定向(301 永久、302 临时、304 协商缓存命中),4XX 客户端错误(400 格式错、401 未认证、403 无权限、404 不存在、429 请求过多),5XX 服务端错误(500 内部错误、502 网关错误、503 不可用、504 网关超时)。工程上最常用的是 200、301、302、304、400、401、403、404、500、502、503、504。
【真题·转述自 计算机网络面试题 - 小林coding】
2. HTTP 到底是不是无状态的?
答(推导 · 已对照解析,转述):协议本身是无状态的,两次请求之间服务器不保留任何上下文,每个请求自带全部信息、互不依赖。这是设计上的选择:服务器不必为每个客户端维护会话,请求可以落到任意一台机器上,扩缩容和负载均衡都容易。但业务需要「记住人」,于是在协议之上用 Cookie 和 Session 补状态,状态存在服务端或客户端,HTTP 的报文格式没变。
【真题·转述自 计算机网络面试题 - 小林coding】
3. Cookie 和 Session 有什么区别?
答(推导 · 已对照解析,转述):Session 是服务端保存的会话数据,Cookie 是浏览器保存的一小段键值,两者配合完成「认人」。典型流程是登录后服务端创建 Session、把 Session ID 通过 Set-Cookie 下发给浏览器,之后每次请求浏览器自动带上这个 ID,服务端查表找回会话。区别在存储位置和安全性:Session 数据在服务端,客户端只拿一个 ID,改不了内容;Cookie 存在客户端,可以被查看和篡改,所以要配合 HttpOnly、Secure、SameSite 使用。
【真题·转述自 计算机网络面试题 - 小林coding】
4. HTTP 强制缓存和协商缓存有什么区别?
答(推导 · 已对照解析,转述):强制缓存是浏览器直接用本地副本、根本不发请求,靠 Cache-Control 的 max-age 判断是否新鲜。协商缓存是每次都要问服务器,请求带上 If-None-Match(对应 ETag)或 If-Modified-Since(对应 Last-Modified),资源没变服务器回 304 且不带响应体,浏览器继续用本地副本;变了回 200 带新内容。前者省掉请求,后者省掉响应体,两级配合。
【真题·转述自 计算机网络面试题 - 小林coding】
5. Cache-Control 里的 no-cache 和 no-store 有什么区别?
答(推导 · 已对照解析,转述):no-cache 不是「不缓存」,而是「用之前必须先向服务器确认」——本地可以存,但每次使用都要走协商缓存校验,未变化时服务器回 304。no-store 才是彻底不存,请求和响应都不许写进任何缓存。前者适合内容会变但想省流量,后者适合涉及隐私或敏感的响应。
【真题·转述自 计算机网络面试题 - 小林coding】
6. 说说 HTTP 常见的请求头有哪些作用?
答(推导 · 已对照解析,转述):Host 指明目标站点,虚拟主机靠它区分,HTTP/1.1 必填;User-Agent 描述客户端身份,用来做设备适配,也是反爬检测的第一道门槛;Referer 记录来源页面,用于流量统计和防盗链;Content-Type 声明正文格式,Content-Length 声明正文长度;Connection 控制连接是否保持;Cookie 携带会话标识,Authorization 携带认证凭证。
【真题·转述自 说说 HTTP 常见的请求头有哪些作用 - CSDN】
状态行给结论、Location 指方向、Header 补上下文,HTTP 的响应侧就是这三件事的组合。评论区聊聊:你见过域名换完之后,老链接还能自动跳过来的情况吗?