注册

面试必问HTTP状态码:从“请求的一生”彻底搞懂,告别死记硬背

HTTP状态码:从请求的一生重新理解



“所有数字背后,都是一个请求的遗言。”


—— 某位被502逼疯的工程师



或者,你也可以记住这一句:



“状态码不是用来背的,是用来收尸的。”


—— 同一位工程师,在又一次凌晨三点被叫起来之后





为什么写这篇文章


相信很多朋友面试的时候都会被面试官问到:“你记得多少HTTP状态码?具体有哪些含义?”


一般对于这类问题,我们都会提前复习和记忆,才能回答得比较完整。


但后来我发现一件事:



“背状态码就像背尸检报告,你记住了死因,却没见过现场。”


—— 某位靠背答案转行写代码的面试者



本文从一个请求离开客户端之后的链路出发,带你去看现场


要彻底搞懂HTTP状态码,我们可以换一种思路:设计这么多状态码,它们具体是在哪一环节、因为什么原因被返回的?


我们的请求传递到整个后端,并不是直接访问到服务器。它要经过一大批网络组件的筛选过滤,每一关都有可能倒下,每一关都会有人替它写下遗言。


下面,让我们从一个请求发送到后端的链路,重新认识一下HTTP状态码。




第一站:边缘节点 CDN



“我以为我能活到源站,结果在门口就被拦下了。”


—— 一个试图直接访问服务器的请求



当一个请求经过DNS解析离开设备,遇到的第一个网络组件是CDN。


CDN是一种缓存设备。它把源服务器的资源拉取到离你最近的地方,像个热情过度的前台:“你要这个?我这有,别往里跑了。”


遇到热门的资源文件(比如B站、抖音的热门视频),直接从CDN获取,速度远远快于访问远端的服务器。对于这些占用带宽较大的静态文件资源,缓存到CDN上是性价比最高的方案。


CDN节点状态码


状态码含义死因报告
200成功命中“我这有,拿去吧。”
304未修改“你手里的还是新鲜的,不用换。”
502回源非法响应“我去帮你问,结果源站说方言,听不懂。”
503回源连接拒绝“源站把门关上了,不让我进。”
504回源超时“源站接了电话,但一直不说话。”


💡 304是个好东西


每次向CDN发起请求,并不一定需要CDN把整个文件再发一遍。


如果我们本地有缓存,带着文件的指纹(ETag)或修改时间(Last-Modified)去问CDN:“我这个还新鲜吗?”


CDN看一眼:“没变,接着用吧。”


省带宽,省时间,双方都舒服。


—— 这是唯一一个**请求和服务器达成共识“你不用干活”**的状态码。





第二站:安全网关 WAF



“我不是不让你进,我是怕你进来搞破坏。”


—— WAF,一个没有感情的安检机器



请求离开CDN后,仍然不能直接到达源站。它先要经过WAF——Web应用防火墙。


这个组件的作用,名字已经写得很清楚:为了安全


它像个眼神锐利的保安,把你从头扫到脚:



  1. 检查IP是否合法 → 不合法返回 403 Forbidden
  2. 检查请求头是否合法 → 不合法返回 406 Not Acceptable
  3. 检查请求体是否合法 → 不合法返回 413 Payload Too Large
  4. 判断请求频率是否正常 → 不合法返回 429 Too Many Requests

WAF状态码场景


攻击/异常类型状态码死因报告
黑名单IP/SQL注入/XSS403“你身上有刀,不许进。”
无效Accept头406“你要的东西我给不了,别进了。”
超大请求体413“你扛的箱子太大了,进不来。”
CC攻击/高频请求429“你来回跑太多次了,歇会儿。”

这些“不正经”的请求方式,其实就是网络安全课里讲的攻击手段。



“我只是想进来看看,它说我是黑客。”


—— 一个带着正常User-Agent却被误杀的公司内网爬虫





第三站:负载均衡器 Nginx



“一万个用户就要一万个进程?凭什么等网速还要占着位置?”


—— Igor Sysoev,Nginx之父,2002年



对于这个组件,一开始我也不明白它为什么有那么多功能。


要认识一件东西,最好的方式是了解它为什么被创造出来




2002年,莫斯科。


Apache的规矩:来一个人开一个进程,来一万个人开一万个进程。


16G内存,Apache张嘴要50G,然后跪了。


Igor Sysoev每天的工作就是重启服务器——像给同一个病人反复做心肺复苏。


终于有一天他骂了句脏话:



“一万个用户就要一万个进程?凭什么等网速的时候还要占着内存?”



他觉得这不合理——像每个客人身后站一个专属服务员,客人上厕所他都得站着等。


Igor决定写一个“不讲武德”的服务器:


一个服务员管五十桌,谁招手过去,谁看菜单就晾着。不等人,不空转,不占茅坑。


两年,一万行C。


2004年,Nginx诞生。


4个进程扛1万连接,内存500MB。


Apache用50G干的活,它用1%的资源。


后来有人问他为什么写Nginx。


他说:



“等的时候,不应该占着位置。”





Nginx核心状态码


场景状态码死因报告
静态文件不存在404“你要的文件,硬盘里没有。”
静态文件无权限403“文件在那,但你不配看。”
后端无响应502“我把请求转给后面,后面没人接。”
后端超时504“后面接了电话,但一直‘嗯’个不停,就是不说话。”
客户端提前关闭499“用户等不及,把网页关了。”
限流拦截429“你刷太快了,我伺候不动。”
主动熔断503“后面的兄弟都快累死了,我先替你挡一下。”


💡 关于499


499是Nginx独有的状态码。


它不是后端返回的,不是WAF拦截的,是Nginx自己记下的遗言:


“他没等我,他走了。”


很多时候你以为的超时(504),其实是用户等得不耐烦,直接关掉了页面。


Nginx默默在日志里写下一行:
“请求已转发,但客户端已失联。”





第四站:Web 应用



“终于到我了。”


—— 一个请求,在穿过CDN、WAF、Nginx之后



终于,请求到达了后端应用。


这里的HTTP状态码,是开发者在代码里亲手写下的


它是唯一一个由你决定生死的环节。




4xx:你的问题,不是我的问题



“你发过来的东西,我尽力了,真的看不懂。”


—— 应用对400说



状态码含义死因报告
400我看不懂JSON少括号、类型传错、必填字段没带
401你没登录没带Token、Token过期、Token被篡改
403你不能进普通用户点管理员接口、IP不在白名单
404我没有查不存在的用户ID、已下架的商品
409已经有了用户名被占用、重复提交、两人同时编辑同一条数据
422内容不对邮箱格式正确但未注册、年龄传了200岁


“你说你叫admin,但我这已经有叫admin的了。”


—— 409 Conflict,注册接口的日常





2xx:一切顺利



“今天是个好日子。”


—— 200 OK,最幸福的状态码



状态码含义遗言(活着的遗言)
200成功“成了,数据给你。”
201创建成功“成了,新资源在这。”
202已接受“收下了,后面慢慢弄。”
204成功,无返回“成了,但没啥可说的。”



3xx:别找我,去那边



“我已经搬家了,这是新地址。”


—— 301,一个负责任的旧门牌



状态码含义死因报告
301永久搬家“这里不住了,以后去那边找我。”
302临时离开“现在不在,你先去隔壁。”
304没变“你手里那个还能用,别下载了。”



5xx:我炸了,不是你的错



“对不起,是我的问题。”


—— 500 Internal Server Error,一个有礼貌的崩溃



状态码含义死因报告
500代码崩溃空指针、数据库连不上、try-catch没接住
502上游乱说话第三方API返回乱码、Redis数据结构不对
503我拒绝连接池满了、服务正在重启
504上游太慢第三方API超时、SQL查了10秒


“我调了别人的接口,别人没回我。”


—— 504,一个被上游坑死的请求





链路简图 · 请求的一生



“这不是架构图,这是事故多发路段示意图。”



20260212-230754.jpeg


写在最后:状态码不是数字,是请求的“尸检报告”


行文至此,我们已经陪着一个HTTP请求走完了它的完整一生。


它从你的浏览器出发,叩开CDN的大门,穿过WAF的安检,经过Nginx的调度,最终抵达应用服务器的后厨。


而在每一道关卡,都有可能倒下——也可能凯旋。


每一个状态码,都不是随机数字,而是请求倒下的那一刻,最后一个活着的人替它写下的死因报告。




当你再看到502,你脑海里应该浮现的不是“Bad Gateway”这行英文,而是一场事故现场:



  • 也许是CDN回源时,源站说了句它听不懂的方言(非法响应)
  • 也许是Nginx转发时,后端的应用根本没在听(连接失败)
  • 也许是你的代码调用第三方API,对方接了电话但开始沉默(超时)
  • 也许是负载均衡器巡视一圈,发现所有小弟都已阵亡(无可用后端)


同一个502,七种死法。症状相同,病灶各异。



这就是为什么,学会背状态码的人只能回答“它是什么意思”,而理解链路的人能回答:


“它死在了哪一环。”




这趟旅程也告诉我们另一件事:


CDN会替你背锅,Nginx会替你扛压,WAF会替你挡刀——但它们都只是过客。


唯一从头到尾、从生到死都陪着你代码的,是你自己写的业务逻辑。


200是你写的,404是你写的,500也是你写的。



状态码不是面试官拷问你的工具,而是你的代码和这个世界对话的语言。



你用200说:“一切正常。”

你用404说:“你找的东西不在这里。”

你用500说:“抱歉,我出了点问题,已经在看日志了。”




所以,别再背状态码了。


去理解你请求走过的路,去读懂每一行日志,去亲手写下每一个你返回的状态码。


当你不再问“502是什么意思”,而是问——



“这个502是谁报的?”

“在哪一环报的?”

“日志里留下了什么线索?”



那一刻,你就不再是背答案的人,而是真的懂了。





“愿你的200永远不鸽,愿你的5xx永远有日志可查。”


—— 同一位被502逼疯的工程师,在最后一次上线后说



作者:YouRock
来源:juejin.cn/post/7605848213602779182

0 个评论

要回复文章请先登录注册