做蜘蛛池的人常常盯着“蜘蛛来了几次”這一個指标,却很少看“每次抓走多少字节”。入口頁里大量内容是不變的連結聚合,如果每次抓取都把整頁 HTML 重新传一遍,服務器带宽和响應時間都會被無谓消耗。缓存头里的 304 机制,就是用来压缩這部分開销的。
304 响應到底發生了什么
当蜘蛛第一次抓到入口頁时,服務器會连同一组校驗标识返回,常见的是 Last-Modified 和 ETag。下一次抓取时,蜘蛛會把這两個值放進 If-Modified-Since 和 If-None-Match 請求头。如果服務器判断内容没變,就回一個 304 Not Modified,响應体為空。
要注意两点:一是 304 依然算一次抓取請求,蜘蛛的訪問計數、日誌记錄都不會少;二是它省下的是传輸内容和部分處理時間,不是抓取次數。所以它解决的是“重复抓同一份内容成本高”的問题,不是“抓得太少”的問题。
哪些入口頁适合開缓存
- 長期不動的連結聚合頁、導航頁、老榜單頁;
- 侧栏、頁脚一類公共区块的静態资源;
- 只承担“把蜘蛛引向目标頁”职责、正文本身不更新的入口頁。
反過来,需要频繁追加新連結的入口頁、狀態碼经常變化的頁面、做跳轉分流的中間頁,都不适合套長缓存,否則中間层可能一直返回舊内容,新加的連結反而更晚被發現。
头部信息怎么寫更稳妥
- Last-Modified 用文件或内容的真實修改時間,別每次請求都寫目前時間,那會让條件請求永遠失效。
- ETag 避免用随進程變化的 inode、進程号、随机數拼接,否則同一份内容每次算出的值都不一样。
- Cache-Control 可以用 max-age 和 s-maxage 做分层,但不要图省事统一寫 no-store,那等于把缓存這條路堵死。
- 两個校驗值不要互相打架。同时给出 ETag 和 Last-Modified 是允许的,但逻辑要一致,否則會出現“這次 304、下次 200”的抖動。
几個常见的理解偏差
第一個偏差是把 304 当成“蜘蛛没抓”。日誌里 304 會正常记一條,只是响應体為空,看訪問记錄时容易被当成無效請求過滤掉。排查抓取断点时如果只統計 200,就會漏掉這部分正常抓取。
第二個偏差是認為開了缓存就能提升抓取频率。缓存只影响传輸体积和响應速度,蜘蛛是否再来、隔多久来,取决于它自己的調度和你頁面释放的更新信号。把缓存当成“催蜘蛛”的手段,方向就错了。
第三個偏差是忽略中間层。CDN、反向代理、WAF 都可能重寫 ETag 或补上 Age 头,你在源站配的值和蜘蛛實际收到的值未必一致。核對时用命令行工具直接看响應头,比凭配置頁面猜要靠谱。
落地时的检查清單
- 先用命令行請求一次入口頁,记錄返回的 Last-Modified、ETag、Cache-Control;
- 用带條件請求的方式再抓一次,確認是否能正确返回 304;
- 抽查服務器日誌,統計入口頁里 2xx 和 304 的比例,看哪些頁面長期重复传輸;
- 内容更新时確認头部同步更新,避免出現“頁面變了但校驗值没變”;
- 按頁面類型分层配置,聚合頁可以放宽,新連結頁保持較短缓存。
缓存是省资源的手段,不是提升抓取的手段。入口頁能被發現、能被重訪,仍然依赖連結结构、内容更新和正常的服務器响應。
把 304 和缓存头理顺,收益通常体現在带宽、响應時間和服務器负载上,而不是抓取條數的立刻上涨。把它当成入口頁运维的一個基础動作,比指望它带来戏剧性變化要現實得多。