404页面有多贵?114个大站说一句没有就要66KB
本文目录
- 一个不存在的地址,站点要花多少字节来回答?
- 先证明这把尺子本身是准的
- 状态码这一关,是不是其实大家都过了?
- 那几百KB里装的到底是什么?
- 八个站,说“没有”比说“有”还贵
- 响应快不快
- 压缩之后真正传出去的是多少?
- 同一个站,为什么 .css的“没有”比网页的“没有”便宜两百倍?
- 还有一件更别扭的事:类型也对不上
- 说“有”的那十一个站,麻烦在哪?
- 它们的noindex和canonical都写了什么
- 平台默认值替你做完了这道选择题
- 缓存头也是默认值的产物
- 把问的节奏放慢,答案会变吗?
- 三个数先量出来,再谈改
- 错误页该长什么样
- 删了商品之后到底该回什么
- 把它挂进哪个流程
- 常见问题解答
- 返回404的页面还需要加noindex吗?
- 错误页几百KB,真的会影响SEO吗?
- 怎么判断我的站是不是软404?
- 单页应用没法在服务端判断地址存不存在,怎么办?
- 不存在的图片和CSS返回整张HTML,除了浪费流量还有别的害处吗?
- 把错误页缓存起来会不会导致真实页面上线后还显示404?
- 410用起来有什么风险?
- 权威参考资料
摘要:对131个国际电商站各要了14个地址,其中11个是编出来的、这世上根本不存在。首页能进的114个站里,103个老老实实回了404或410,只有11个嘴上说“有”。状态码这一关几乎人人及格,可代价藏在别处:一句“没有”,压缩后中位数还要传66.1KB,解压开是363KB,最大的那个站解压后5.73MB。这个数字是首页的0.83倍——服务器说“我没有这个东西”,花掉的带宽跟它把整个首页端出来差不多。
事情的起因很土。上个月帮一个做宠物用品的独立站看抓取日志,发现Googlebot有相当一部分请求打在一批早就删掉的商品地址上。这不稀奇,改版之后总有这种尾巴。稀奇的是把那些请求的响应大小拉出来一看,每一条都在两百多KB。
一个已经不存在的页面,凭什么还要传两百多KB?
于是就有了这次普查。131个国际电商站,每个站要14个地址:两个是真实存在的(首页和robots.txt,当对照组),十一个是随手编出来的、这世上不可能存在的路径,还有一个是把同一个不存在的地址再要一遍。想知道的事情很简单——当你朝一个站要一件它没有的东西,它是怎么回答你的,以及这句回答要花多少钱。
一个不存在的地址,站点要花多少字节来回答?
先说结论,再说怎么来的。首页能正常打开的有114个站,其中103个对不存在的地址给出了404或410。这103个站的错误页,压缩之后传输量中位数67722字节,也就是66.1KB;解压开是371962字节。
66KB听起来还行?那就换个参照物。同一批站的首页,用同样的方式量一遍,错误页跟首页的传输量之比中位数是0.83。有12个站的错误页比自己的首页还大。
| 口径 | 中位数 | 最大 | 超过100KB的站 |
|---|---|---|---|
| 压缩后(真正走网线的字节) | 66.1KB | 521KB(rab.equipment) | 30个 |
| 解压后(浏览器要解析的字节) | 363KB | 5.73MB(misen.com) | 88个 |
解压后超过1MB的有16个站,超过512KB的有38个。排在最前面的那几个,misen.com 5729744字节、burrow.com 4649467字节、dreametech.com 3308733字节、eufy.com 2604079字节、casetify.com 2587949字节。这些数字后面跟着的都是知名品牌,不是什么野路子小站。
顺便说一句,2.6MB这个量级已经越过了Googlebot抓取体积的常见讨论线。一个用来告诉爬虫“这里什么都没有”的页面,体积够得上一次正经的正文抓取。
先证明这把尺子本身是准的
在往下走之前得先过一关。任何“A和B不一样”的结论,前提都是“A和A自己一样”。所以每个站上都多要了一次同一个不存在的地址,看两次回来的字节对不对得上。
结果:114个站里,两次字节完全相同的40个,相差不到2%的74个,一个不稳的都没有,抖动的中位数是0字节、最大216字节。另外还编了第二个完全不同的不存在路径,两个路径的状态码114比114全部一致。
更狠的一层对照是跨轮的。这次普查前后跑了两轮,中间隔了将近一个小时。两轮都返回404的65个站,字节相对差的中位数是0.0000,差得最多的philips.com也只有0.9%。同一个站隔一小时问两次,它说“没有”的方式一个字节都不带变的。
这一步不能省。之前量爬虫和用户看到的页面差异那次就吃过亏——不补对照组,量出来的74%差异有七十多个百分点是页面自己的抖动。这回先把零点钉死,后面所有的差异才站得住。
状态码这一关,是不是其实大家都过了?
是,而且过得比预想的漂亮。114个可判定的站里:
- 返回404的102个
- 返回410的1个(zwilling.com,唯一一个用410 Gone的)
- 返回200的11个
诚实率90.4%。这跟很多人的印象不太一样——业内讲软404讲了十几年,好像遍地都是。至少在这批体量的电商站上,状态码这道题基本都做对了。
更有意思的是稳定性。六种不同形态的不存在路径都试了:根目录下的、带尾斜杠的、塞进/products/里的、塞进/collections/里的、四层深的、带.html后缀的。六种形态返回404的站数分别是102、101、103、101、103、102,上下浮动不超过2个站。站点对“不存在”的判断跟路径长什么样几乎没关系,这说明这个逻辑写在很靠前的地方,多半是平台或框架的默认行为,不是谁一条条配出来的。
这跟同一个页面十一种写法都返回200那次量到的结论是一枚硬币的两面:路径归一化跑在你写的所有规则之前,存在的东西被它放宽,不存在的东西也被它统一挡住。
所以真正值得聊的不是“有没有回404”,而是回这个404的时候顺手做了些什么。
那几百KB里装的到底是什么?
把错误页的HTML拆开数了数:103个站的404页面上,<a>标签数量中位数97个、最多1703个;<script>标签中位数39个、最多230个。
这就说清楚了。那几百KB不是错误信息,是整张站点外壳:头部导航、巨型下拉菜单、页脚的全部链接、语言切换、货币切换、Cookie横幅、客服挂件、埋点脚本、A/B测试脚本、推荐引擎、评价挂件。用户走错门,站点把整个商场的平面图连同全部导购一起塞给他。
体感上这挺贴心。可对爬虫来说,它拿到的是一份跟另外几千个页面高度雷同的模板,正文区域写着“页面不存在”。
八个站,说“没有”比说“有”还贵
按解压后的字节算,错误页跟首页之比超过1的有8个站;按压缩后的传输量算是12个。最极端的几个:
| 站点 | 404页字节 | 首页字节 | 比值 |
|---|---|---|---|
| sostrenegrene.com | 72263 | 38314 | 1.89 |
| dji.com | 317079 | 168217 | 1.88 |
| casetify.com | 2587949 | 1464059 | 1.77 |
| montbell.com | 139927 | 88445 | 1.58 |
怎么会有这种事?首页通常是全站优化最狠的一个页面,图片懒加载、脚本延迟、首屏内联,能砍的都砍过。而404页面没人管,它继承的是那套没被优化过的原始模板,该加载的一样不少,该延迟的一个没延迟。优化过的页面和没人管的页面放在同一个站上,差距就是这么来的。
响应快不快
耗时这一栏反倒还行:404的响应时间中位数509毫秒,首页是815毫秒。最慢的几个是segway.com 2940毫秒、braun.com 2478毫秒、assos.com 2326毫秒。
比首页快是意料之中的,毕竟不用查数据库。但两三秒的错误页仍然值得警觉,那说明这个页面在渲染时还在跑一整套业务逻辑。慢查询和抓取预算那笔账在这里同样成立,只是账单开在了一个不存在的地址上。
压缩之后真正传出去的是多少?
这一节是自己给自己纠的偏,写出来是因为踩这个坑的不会只有保哥一个。
第一轮跑完,手上的数字是“错误页平均621745字节”。这个数听着骇人,六十多万字节。差点就这么写出去了。
问题在于,HTTP客户端默认会替你把响应解压,你拿到的len(body)是解压之后的长度。而抓取预算、带宽账单、CDN流量费,算的全是压缩之后真正走网线的那些字节。这两个口径在这批站上差了5.5倍。
所以又跑了一轮,这次不解压,直接数原始字节流:
- 压缩后中位数67722字节,解压后中位数371962字节,压缩比中位数0.18
- 用Brotli的75个站,用gzip的21个,用zstd的1个,一点不压的5个站
- 压缩后超过100KB的30个站,超过500KB的只剩1个(rab.equipment,521KB)
纠偏之后结论没有反转,只是变得能站住脚了:66KB依然是一个不小的数,尤其考虑到它对应的信息量是“没有”这两个字。但5.73MB那种说法只能用在“浏览器要解析多少”这个语境里,不能拿去算带宽。
那5个完全不压缩的站要单独说一句。压缩类型的配置盲区在别处也常见,nginx出厂只压HTML这一种类型,其余的全额计费。放在错误页上,不压缩意味着它的传输量直接等于解压后的体积。
同一个站,为什么 .css的“没有”比网页的“没有”便宜两百倍?
这是这次普查里最硬的一组对照,因为它发生在同一个站、同一次会话、同一个CDN后面,唯一的差别只是要的东西后缀不一样。
同样是不存在的地址,请求/xxx和请求/xxx.css,中位数分别是:
| 请求形态 | 字节中位数 | 耗时中位数 |
|---|---|---|
| 网页路径(/xxx、/products/xxx等六种) | 371983 - 385587 | 271 - 342毫秒 |
| 不存在的 .css | 1970 | 256毫秒 |
| 不存在的 .js | 1708 | 241毫秒 |
| 不存在的 .jpg | 338402 | 468毫秒 |
中位数上 .css只要1970字节,跟网页路径差了将近两百倍。但平均数是280157字节——这个巨大的落差说明样本裂成了两半。逐站看确实如此:52个站的资源形态明显更省,51个站两者一样大,一个反过来的都没有。
省下来的那一半是怎么做到的?服务器在路由的最外层就按后缀判断了:这个请求要的是静态文件,静态文件目录里没有,直接吐一个几十字节的空响应,连应用框架都不惊动。brompton.com是个漂亮例子,不存在的 .css回21字节、.js回22字节、.jpg回一个78字节的透明GIF,而同一个站不存在的网页路径回215528字节。
另一半没这么做的站,请求走进了框架的兜底路由,然后框架尽职尽责地渲染了整张错误页——哪怕请求头上明明白白写着我要的是一个样式表。省得最多的几个站落差惊人(按.css、.js、.jpg三种形态的平均算):misen.com从5729744字节掉到1909828,ouraring.com从1226885掉到26743。后者才是这条路径该有的样子。
还有一件更别扭的事:类型也对不上
顺手统计了返回的Content-Type:
- 请求 .css,回
text/html的54个站,占52.4% - 请求 .js,回
text/html的54个站,占52.4% - 请求 .jpg,回
text/html的98个站,占97.0%
图片这一项几乎全军覆没。101个站里只有一个(brompton.com)老实回了image/gif。也就是说,浏览器去要一张图,服务器回了一份几百KB的网页,还盖着“这是网页”的章。浏览器当然不会把它当图片渲染,最终效果是一个碎图图标,代价是几百KB的传输和一次完整的服务端渲染。
这个坑在nginx配置的静默副作用里属于同一族:配置本身不报错,reload每次都通过,只有在“请求一个不存在的东西”这条冷门路径上才现原形。爬虫报的死链和Googlebot实际抓的从来不是同一批,一部分原因也在这儿。
说“有”的那十一个站,麻烦在哪?
11个站对不存在的地址返回了200。名单:aliexpress.com、govee.com、iittala.com、innisfree.com、kotn.com、narwal.com、on.com、prose.com、shein.com、temu.com、zalando.com。
两个最大的跨境平台都在里面,这一点挺说明问题的。
它们的表现分三类。第一类是跳走:aliexpress.com跳了三次最后落到一个404页面上、govee.com和iittala.com各跳一次回首页。跳到首页这种做法,Google官方文档里点名说过,会被判成软404,因为地址变了、状态码却是200,搜索引擎只能自己猜。
第二类是原地返回一个壳:innisfree.com回了1802字节的空HTML,temu.com 2910字节,on.com 4348字节,narwal.com 4973字节。这些都是单页应用,路由在浏览器里,服务端根本不知道这个地址存不存在,先把壳发给你再说。前端框架站的渲染模式选择在这里直接决定了状态码能不能给对。
第三类最贵:govee.com回了3273316字节、shein.com回了1133975字节,都是200。一个不存在的地址,换来3.2MB的200响应。
它们的noindex和canonical都写了什么
这11个站里,页面上带noindex的只有kotn.com一个。canonical方面,govee.com指向https://us.govee.com、shein.com指向https://sg.shein.com/、prose.com指向/,其余的干脆没有canonical。
值得说明的是,没有一个站的canonical指回这个不存在的地址自己。所以这批200不至于变成无限的索引空间——canonical至少把它们归并到了首页那一边。但canonical是提示不是命令,Google会自己选规范页;人机验证屏被当成正文索引那个案子就是这么翻车的。真正该做的是把状态码给对,而不是指望后面几道闸兜住。
对照一下正常返回404的那103个站:带noindex的21个,带canonical的72个,两样都没有的21个。404页面本身不需要noindex,状态码已经把话说完了,这21个属于多做了一步也不亏。反过来,接口和feed这类没有head标签的地址就只能靠响应头说话,状态码在那里更是唯一的表达手段。
平台默认值替你做完了这道选择题
按建站平台分组,压缩后的传输量中位数是这样:
| 平台 | 站数 | 404传输量中位数 | 说“有”的站 |
|---|---|---|---|
| Shopify | 59 | 81091字节 | 2 |
| Magento | 3 | 98115字节 | 0 |
| 认不出平台 | 18 | 54383字节 | 9 |
| Salesforce Commerce | 10 | 35062字节 | 0 |
| BigCommerce | 2 | 37488字节 | 0 |
| Next.js | 10 | 25081字节 | 0 |
Next.js那一组是最省的,中位数25KB,只有Shopify的三分之一。原因不神秘:Next.js有一个约定俗成的not-found页面,默认长什么样就是什么样,很多团队根本没动过它,于是它保持了一个极简的形态。而Shopify主题里的404模板挂在完整的layout下面,导航、页脚、全套挂件一个不少。
说“有”的11个站里,有9个落在“认不出平台”这一组。这一组基本是自研或者重度定制的站,恰恰是最容易漏掉这条路径的一类——用现成平台的时候,这道题平台替你答了;自己写的时候,就得自己记得答。
缓存头也是默认值的产物
顺手看了404响应的Cache-Control:写private, no-store的46个站,压根没这个头的14个,其余是各种no-cache组合。
这意味着绝大多数站的错误页是每次现做的,同一个不存在的地址被要一万次,服务端就渲染一万次。对一个内容永远不变的响应来说,这个默认值不太合理。多层缓存那套逻辑在这里可以反过来用:错误页恰恰是最适合被边缘节点缓存的东西。
把问的节奏放慢,答案会变吗?
会变,而且变得很不讲道理。这一节是方法论,但它同时是这次普查里最贵的一个教训。
第一轮用的是4个并发、每个请求之间隔0.35秒,跑完发现36个站返回429,也就是“你要得太快了”。这些站的数据全废了。
于是把节奏放慢到2个并发、间隔1.6秒,整批重跑。结果:
- 429的站从36个降到6个
- 37个站从被拒变成能进
- 但有7个站反过来了:快的时候能进,慢下来反而被拒(allbirds.com、aloyoga.com、avocadogreenmattress.com、awaytravel.com、baseus.com、beistravel.com、swarovski.com)
如果只看前两条,很容易得出“放慢就能绕过限流”这个结论。第三条把它否掉了。限流不是一条你放慢就一定能压到线下的曲线,它按时间窗计数,你慢下来只是换了一个窗口落脚,运气不好照样撞上。
这件事对做SEO的人有直接的用处。限速规则拒掉的第4个请求要是robots.txt,全站抓取会停十几个小时;抓取速率被调低的那几天,服务器日志里可能一条错误都没有。爬虫也是这样,在别人的限流窗口里碰运气。
还有一层:那17个始终没进去的站(403十个、418一个、429六个),它们只能算“判不了”,不能算“没有404页面”。把判不了的样本混进分母是一种很常见的作假,哪怕是无意的。
三个数先量出来,再谈改
这件事的排查成本极低,低到没有理由不做。三条命令,一分钟:
curl -s -o /dev/null -w "%{http_code} %{size_download}\n" \
-H "Accept-Encoding: gzip, br" https://你的域名/zwb-not-exist-9x8
curl -s -o /dev/null -w "%{http_code} %{content_type} %{size_download}\n" \
https://你的域名/zwb-not-exist-9x8.css
curl -s -o /dev/null -w "%{http_code} %{content_type} %{size_download}\n" \
https://你的域名/zwb-not-exist-9x8.jpg第一条看状态码和传输量,第二三条看后缀路径有没有被短路掉。注意size_download在带Accept-Encoding时给的是压缩后的字节,正是你要的那个口径。用curl -I查响应头有它自己的坑,这里必须用GET。
拿到三个数之后对号入座:
| 症状 | 该改哪里 | 大概能省多少 |
|---|---|---|
| 状态码是200 | 先修状态码,其它都是后话 | 决定性的 |
| 状态码对,传输量 > 100KB | 给错误页做一套精简模板,砍掉巨型导航和第三方挂件 | 本批实测可降到25KB一档 |
| .css/.jpg也返回整张HTML | 在服务器层给静态后缀加一条兜底规则,不进应用 | 单次省掉99%以上 |
| Content-Type与后缀对不上 | 同上,顺带把类型给对 | 省的是浏览器的困惑 |
| Cache-Control是no-store | 允许边缘节点缓存错误页 | 省的是服务端渲染次数 |
错误页该长什么样
不用做成极简的白底黑字,那样用户体验会掉。合理的做法是给404单独一套模板:保留品牌头部、一个搜索框、几条主要分类的链接,其余全砍。参照本批数据,25KB那一档是完全做得到的,而且视觉上并不寒酸。
要砍的重点是第三方挂件。中位数39个<script>里,真正跟“告诉用户走错了”有关的一个都没有。评价挂件、推荐引擎、A/B测试框架、客服机器人,在一个不存在的地址上全都无事可做,却照样被下载和执行。
删了商品之后到底该回什么
顺带说个常被问的:商品下架了,地址该回404还是410?404的意思是“我不知道这里有没有东西”,410的意思是“确实有过,我确认它没了”,两者的正式定义都写在RFC 9110的状态码那一章里。哪些死链必须修、哪些纯属白费功夫那篇讲过判据:有替代品就301到替代品,没有替代品且确定不回来就410,拿不准就404。
本批103个说“没有”的站里只有zwilling.com一个用了410。这不是说其他人做错了,只是说明这个区分在实践中基本没人做——而对搜索引擎来说,410确实能让它更快地把这个地址从索引里拿掉。
把它挂进哪个流程
这不是一次性的活。改版、换主题、上CDN、换框架版本,都可能把这条路径改回去。合适的做法是把上面三条curl写进上线后的冒烟检查,跟可索引性体检放在一起跑。死链检测查的是“该活的活没活”,这一项查的是“该死的死得干不干净”,两边合起来才是完整的。顺带把站点地图里那些已经坏掉的网址一起筛一遍,那批地址正是爬虫撞上错误页的主要来源。
保哥这些年见过最离谱的一次,是一个站把404模板挂在了带商品推荐的layout下面。推荐引擎每次都要查一遍数据库,于是每一个爬虫撞上的死链,都在数据库上开了一次全表扫描。分面导航生成的海量URL撞上这种配置,就是一场没有尽头的自我攻击。
常见问题解答
返回404的页面还需要加noindex吗?
不需要。状态码404本身已经告诉搜索引擎这个地址不该进索引,再加noindex是重复的。本批103个正常返回404的站里有21个加了,属于多做一步不亏,但没加的82个也不构成问题。真正需要noindex的是那些状态码给不对、只能返回200的场景,而那11个返回200的站里恰恰只有一个加了。
错误页几百KB,真的会影响SEO吗?
影响的是抓取预算,不是排名。Google关于大型网站抓取预算的说明里把软404单列成一项浪费,理由正是这个:爬虫每天在你站上的额度是有限的,花在错误页上的字节和请求数就是从正经页面那里挪走的。对几百个页面的小站这笔账可以忽略,但对商品动辄上万、改版频繁、死链存量大的电商站,这是一笔实打实的开销。判断标准很简单:去日志里看爬虫每天撞多少次404,乘以你刚量出来的那个传输量。
怎么判断我的站是不是软404?
用curl请求一个绝对不存在的地址,看返回的状态码。是200就是软404,无论页面上写着什么。要特别注意跳转到首页这种做法,最终状态码是200、地址也变了,这在搜索引擎那里同样算软404。Search Console的覆盖率报告里也有专门一栏,但它是抽样的、有延迟,自己curl一下更快。
单页应用没法在服务端判断地址存不存在,怎么办?
三条路。一是给路由做服务端渲染或预渲染,让服务器知道哪些地址是有效的;二是用框架自带的not-found约定,让构建期就生成正确的错误响应;三是退而求其次,在边缘节点上维护一份有效地址清单,命中不了的直接由CDN返回404。第三条最容易落地,代价是清单要跟着内容更新。
不存在的图片和CSS返回整张HTML,除了浪费流量还有别的害处吗?
有。浏览器拿到一份Content-Type是text/html的响应去当样式表用,会直接拒绝应用,控制台报一条MIME类型不匹配。如果这个样式表恰好是首屏关键的那一份,页面会以裸HTML的形态渲染一瞬间。更麻烦的是这类问题在本地开发环境几乎不出现,因为开发服务器的静态目录和线上不是一回事。
把错误页缓存起来会不会导致真实页面上线后还显示404?
会,所以缓存时间要短,几分钟到一小时是常见的取舍,同时上线流程里要有清缓存这一步。更稳的做法是只在CDN层缓存、不在浏览器层缓存,这样你随时可以主动刷掉。风险确实存在,但跟每次都回源渲染一整套模板相比,多数站点的天平是倒向缓存这一边的。
410用起来有什么风险?
410表示“确认没了、别再来了”,语义比404强。风险在于它不可撤销的味道太重——如果这个商品以后还会上架、或者这个地址只是暂时下线,用410会让搜索引擎更快地把它清出索引,回来的时候要重新爬一遍。判据是“这个地址还有没有回来的可能”,没有就用410,有就用404。
权威参考资料
本文标题:《404页面有多贵?114个大站说一句没有就要66KB》
本文链接:https://zhangwenbao.com/404-page-crawl-budget-byte-audit.html
版权声明:本文原创,转载与引用请注明作者与原文链接。许可协议: CC BY 4.0