为什么一张图片加载失败,页面其余部分却正常
三个条件可以把网络故障、被拦截的请求和渲染错误区分开。在改路径之前,先找出浏览器实际选中的 URL。
页面加载完成,文字正常显示,只有一张图变成了破碎的图标。第一反应是怪隧道,因为隧道正是那个变了的东西。在那之前,先弄清楚浏览器究竟为这张图请求了哪个 URL,因为页面 URL 和图片 URL 是两份不同的证据。大多数图片丢失的报告最终都落在一个从未收到可用请求的主机上,而这个答案只需看一眼网络面板。
三个条件决定该往哪里看
第一个条件是图片是否与页面来自同一台主机。单独的图片主机需要自己的域名解析、自己的连接和自己的 TLS 身份,所以页面能加载并不能说明它的情况。
第二个条件是浏览器是否在发出请求之前就把它拦下了。混合内容、内容安全策略和 referrer 规则都能让一张图被拦下而不产生普通的服务器响应,因此列表里根本看不到失败的请求。
第三个条件是投递成功而渲染失败,也就是字节到了、图却仍然不显示。这三个条件对应三个不同的负责人,只有第一个才是网络问题。
| What you see | Where the fault sits |
|---|---|
| Request absent from the list | Markup, lazy loading or a policy that blocked it |
| Request failed or timed out | Resolution, route, TLS or the image host itself |
| Request returned 200, image blank | Response type, decoding or rendering |
找出浏览器实际选中的资源
你在页面源码里看到的 URL,往往不是被请求的那个 URL。源集、picture 元素和 CSS 背景都会让浏览器根据视口宽度、像素密度或格式支持选择另一个资源。懒加载的图片在页面进入某个状态之前可能根本不会被请求。
把元素和请求放在一起看,报告问题时保留发起者信息。图片元素参考(MDN)在一处讲清了源选择、加载行为和 referrer 控制,足以判断是哪个属性选中了出错的 URL。
记录主机名、状态码、任何重定向链以及响应的内容类型。返回登录页的 200 不是一个可用的图片,而重定向到 HTML 错误页在读到类型之前看起来和损坏的文件一模一样。
先读状态,再看网络
超时、请求被拒和解码错误需要不同的后续步骤,而区分它们的是状态码。超时指向解析、路由或不应答的主机。请求被拒指向策略或授权层。解码错误指向字节或格式。
如果请求根本没有出现,就不要再盯着网络,而要看标记。最常见的原因是源集里有一条浏览器优先选中、但服务器上已不存在的记录,其次是一个脚本从未让它可见的元素。
仅凭这一区分,就能避免这类报告里的大部分无用功。
浏览器拦截时,没有响应可读
混合内容是典型情况:HTTPS 页面通过明文 HTTP 请求一张图,请求被拦下而不是失败,控制台会记录原因。内容安全策略会产生同样的形态,消息里会点名被拦下的指令。剥离 referrer 的策略也可能让防外链的主机返回占位图而不是原图。
在动网络路径之前先读已记录的原因,因为路由改变并不会让这类拦截变好。增加跨源权限也不是解法:显示另一台主机的图片和在 canvas 里读取它的像素是两回事,只有后者才需要人们常粘贴的那些响应头。
对于你管理的网站,在资源所有者那边修正资源 URL、响应或策略,并保持授权与 referrer 的要求不变。对于你无法控制的网站,把页面和请求证据发给它的支持渠道,而不是转载私有或会过期的资源链接。
在不改变证据的前提下比较路径
如果你确实想测试访问路径,就把其他一切固定住:同一个页面、同一个账号、同一张选中的图片,只改一条被允许的路径。比较请求条目而不是渲染结果,因为渲染结果只说明图有没有出现,不说明为什么。
在新路径上加载成功,并不能证明该路径已获授权;图片一直坏着,也不能证明是隧道的错。如果图片已被删除或访问被有意限制,请使用受支持的替代方案,而不是关闭证书校验或复制他人的受保护素材。
工作顺序:确定选中的 URL,读取它的状态和类型,检查是否有已记录的拦截原因,然后一次只比较一处路径改动。