GeoJSONcn
GeoJSONcn / 技术专栏 / GeoJSON 迟迟不更新?HT…

GeoJSON 迟迟不更新?HTTP 缓存三兄弟 Cache-Control、ETag、Last-Modified 治陈旧边界

发布于 2026-08-20 · GeoJSONcn 技术团队 · 阅读约 11 分钟

做行政区划下载站的人大概都经历过这个场景:凌晨把最新的全国省市区县geojson数据下载好、清洗完、上传上线,结果白天用户打开页面,看到的还是三个月前那批旧边界,连乡镇并村都还是老名字。明明文件换了,浏览器和 CDN 就是抱着旧的不撒手。这不是数据的问题,是 HTTP 缓存没管好。做 GeoJSON下载 这块尤其容易中招——本文就把 GeoJSON 数据在浏览器缓存和边缘 CDN 两侧的缓存策略讲透,特别是静态站改完数据想让线上立刻新的那套做法。

一、先搞清楚你被哪一层缓存卡住了

一张地图页加载 province.json,可能同时被三处缓存命中:浏览器本地缓存、CDN 边缘缓存(比如我们 geojsoncn 用的 Cloudflare、你手上的阿里云 ESA/EdgeOne)、以及最容易被忽略的服务器响应头。排查顺序有讲究,先看浏览器再回溯更上游。

用一条 curl -I 就能看响应头里到底有没有缓存指令:

curl -sI https://geojsoncn.com/data/province.json
# 关注这几行:
# Cache-Control: public, max-age=31536000, immutable
# ETag: "a1b2c3..."
# Last-Modified: Wed, 20 Aug 2026 03:00:00 GMT

Cache-Control: max-age=31536000 意味着这份数据一年内浏览器根本不回源,immutable 更是告诉浏览器"这个文件永远不会变"。对真的不变的数字资产(带版本号的文件名)这完全合理;但对会更新的 province.json 这种裸 URL,就是慢性毒药——你换文件它照样用旧的。所以第一课:静态资源的 max-age 要和"文件名会不会变"绑定。

资源类型推荐 Cache-Control理由
带哈希/版本号数据包(province-v2026.08.geojson)public, max-age=31536000, immutable文件名变了 URL 就变,放心长缓存
裸 URL 数据文件(province.json)public, max-age=300 或 no-cache允许短期缓存又要能更新
文章/索引 HTML(index.html、articles)no-cache + ETag内容频繁变,每次回源校验
静态 JS/CSS/PNG 资产public, max-age=31536000, immutable版本化文件名,长缓存

拿 geoJSON 数据下载实操对号入座:只要文件名换来换去,就归到长缓存那两行;文件不变只内容变,就归到 304 协商那两行。

二、改完数据想让线上立刻新?靠 ETag 而不是清缓存

很多人一改数据就急着"刷新 CDN 全站缓存",其实这是最粗暴也最伤的方式——尤其像按主机名全站刷,可能连静态资源里面的智能压缩配置都给误触发,把好好的 JSON 搞坏。做全国省市区县区划边界数据下载这行的,最怕这种误伤。正确的动作是:数据文件用 ETag + 短 max-age,更新时靠浏览器 304 协商。

ETag 就是文件内容的指纹,只要内容变了指纹就变。给 province.json 配 Cache-Control: public, no-cache(注意是 no-cache,不是 no-store),浏览器每次都会带着旧文件的 ETag 回源问一句"我这份还新吗?";服务器比对发现变了,返回新内容 + 新 ETag;没变就回 304,几乎不耗流量。这样既不用每次全量拉几百 KB 的 GeoJSON,又能保证改完下个请求就是新的。

如果你用的是纯静态站 + R2/OSS 这类"上传即覆盖"的对象存储,很多平台会在同路径覆盖时自动重算 ETag,你基本不用手工碰。需要自己算的场景(比如自定义源站),统一用文件 SHA-256 前 16 位当 ETag 即可,和之前讲过的校验和能对上号。

// 静态生成时给数据文件外挂一个 .headers 声明(示例,按你平台格式调整)
// 让 province.json 走 304 协商,而不是闷头缓存一年
{
  "data/province.json": {
    "Cache-Control": "no-cache",
    "ETag": "a1b2c3d4e5f60718"   // 内容 SHA-256 前 16 位
  }
}

三、全国村级 GeoJSON 数据这种"低频更新大文件"怎么权衡缓存时间

村级边界数据更新频率低(往往半年甚至一年才动一次),但单文件大(几 MB)。对这种文件,我建议反过来:文件名带上版本号 + 长缓存,而不是靠 ETag 天天协商。做全国村级geojson数据下载时这个策略尤其香。

理由很直接:村级文件大,如果每天都被浏览器带着条件回源请求一次,边缘回源开销也不小;而它一年才更新一两次,用版本号文件名反而最省事——旧版本让 CDN 自然过期,新版本 URL 天然是新的,两边都不需要强制刷新。v2026.08.csv、village-2026.08.geojson 这种命名,配合 immutable,用户侧零回源、边缘零 MISS,体验最好。

但要记得配套做两件事:一是下载页 HTML 里的链接要跟着版本号变(否则页面还指着旧版本号);二是老版本文件别急着删,留一个窗口期给 CDN 边缘缓存自然过期,避免 404。我之前踩过坑:升级完把旧文件直接清了,结果边缘缓存还存着旧链接,用户一上午都在下载 404。

四、收尾:一套可复用的"更新而不翻车"四步

把上面串起来,一个行政区划下载站的数据更新应该这么做:

1. 先对比再上线:用 adcode 作主键比对新旧两个 GeoJSON,确认是新数据再发布,别把半成品传上去(这能省下后面所有缓存麻烦)。 2. 裸 URL 走短缓存/协商:province.json、cities.json 这种不换名字的,配 no-cache + ETag,更新即生效。 3. 低频大文件走版本号:村级等更新慢的大文件,文件名带版本 + 长缓存,新链接天然刷掉旧的。 4. 只在必要时精准刷新 CDN:确实要手动刷时,用 Type:file 精刷具体 URL,千万别按主机名全站刷,更别在数据文件那台边缘上开智能压缩。

这套组合下来,无论你是做省市县镇四级数据的 GeoJSON 下载站,还是拿全国省市区县 geojson 数据做地图可视化,都能让"改完数据线上立刻新"和"边缘缓存少回源"这俩目标同时成立——既不伤性能,也不误伤文件。

---

*本文讨论的缓存策略均基于通用 HTTP 规范和静态对象存储的上传即覆盖模型,与具体地图 API、边界数据本身无关。*