天地图 403 Forbidden 排查:tk 密钥与 Referer
1. 打开控制台看到一片403先把问题边界划清楚如果你正在做地图相关的开发或者用 ArcGIS、ArcGIS Pro 往项目里挂在线底图那么遇到403 Forbidden这个状态码几乎是迟早的事。我印象比较深的一次是帮朋友排查一个已经上线跑了半年的系统某天早上突然所有底图瓦片全部变成灰色控制台里密密麻麻全是403 Forbiddened顺带说一句正确写法是Forbidden正文里常见到的Forbiddened是拼写惯性。当时第一反应是网络挂了第二反应是天地图服务停了折腾了大半天才发现根子出在一个谁都没想到的地方——tk 密钥绑定的域名和实际请求的 Referer 对不上。天地图国家地理信息公共服务平台提供的是一整套在线地理信息服务包括矢量底图、影像底图、地形晕渲、各类注记图层以及地名搜索、逆地理编码这类接口。它本身是公开、免费的但免费不等于无门槛所有的瓦片和接口调用都要带一个叫tk的令牌参数。这就意味着403这个错误几乎全部和身份校验相关而不是服务不存在。理解这一点非常关键因为它直接决定了你该往哪个方向排查。提示403是服务器听懂了你的请求但拒绝为你服务和404资源找不到、401没带凭证完全是三码事。很多人一看到底图加载失败就去检查 URL 拼写方向从一开始就偏了。1.1 天地图提供的不止一张底图新手最容易犯的认知错误是把天地图当成一个网址。其实它是一组服务按图层类型和投影方式拆得很细。常见的几个矢量底图vec球面墨卡托版本是vec_w经纬度版本是vec_c影像底图img对应img_w、img_c地形晕渲ter矢量注记cva中文注记、eva英文注记影像注记cia这些图层的请求地址、参数结构各不相同。更麻烦的是不同图层如果开通权限不一致或者某些服务在你的账号下没有申请就会直接返回403。所以排查的第一步永远是确认你请求的到底是哪一个服务以及这个服务你是否已经开通。1.2 403和404、401的区别决定了排查方向我把这三个状态码放在一起对比是因为实际排查中经常有人混淆状态码含义常见触发原因排查方向401未授权完全没带 tk或 tk 参数名写错检查 URL 里有没有 tk 参数403禁止访问tk 无效、域名不匹配、配额超限、IP 未报备校验链路问题404资源不存在图层名拼错、服务路径写错核对官方文档的 URL 模板看这张表就能明白只要出现403你就不用去怀疑 URL 拼错或者图层不存在了问题一定出在身份或来源上。这个判断能帮你省下大量无效时间。我自己给自己立过一条规矩——看到 403第一件事就是打开请求详情看请求头里的Referer和 URL 里的tk九成问题在这两处。2. tk密钥才是重灾区八成的403从这里找排查过几十次天地图403之后我总结出一个经验值大约八成的 403 都和 tk 密钥相关。要么密钥本身有问题要么密钥的使用方式有问题。剩下的两成才是网络、代理、Referer 这些链路问题。所以先把 tk 这一块彻底搞清楚性价比最高。2.1 申请tk时那些容易被忽略的填写项天地图的 tk 是在开发者控制台里创建应用后生成的。整个流程本身不复杂但有几个填写项新手几乎必踩第一是应用类型。如果你是在网页前端浏览器里直接调用瓦片那要选浏览器端如果是在服务器、后端 Java 程序、桌面软件里调用那是服务端类型。这两种类型的校验逻辑不一样选错了会导致要么前端被拦要么后端被拦。第二是域名或 IP 的填写。浏览器端应用通常要求填调用的域名服务端应用一般要求填服务器的公网 IP或者填一个通配值。这里有个真实的坑你填的 IP 必须是请求最终出去的那个公网 IP而不是服务器网卡上配置的内网 IP。云主机、容器、负载均衡后面的机器出网 IP 和机器上的 IP 往往是两回事。第三是tk 会过期或者被重置。如果你重置过密钥或者控制台里重新生成过一定要记得同步替换所有引用它的地方。我见过最离谱的案例是代码里写死了旧 tk 的副本散落在七八个文件里改漏了其中一个结果那个模块的底图全挂。注意不要把 tk 当成可以随便公开的东西。它绑定你的账号和配额一旦泄露别人用你的额度调用超限之后倒霉的是你自己。2.2 域名/IP绑定的校验逻辑很多人不理解为什么浏览器直接粘贴 URL 能打开代码里请求就 403。核心原因就在这个绑定校验上。天地图服务端在收到请求时会做几件事先看 tk 是否存在且有效再看这个 tk 创建时声明的来源类型然后根据来源类型去校验请求头里的Referer浏览器场景或请求的来源 IP服务端场景。浏览器直接打开 URL浏览器会自动带上一个和当前页面相关的Referer头如果这个来源恰好和 tk 绑定的域名一致就通过了。但你在 Java 或 Python 代码里发请求时很多 HTTP 客户端默认是不带 Referer 头的于是服务端一看来源为空或者不匹配直接拒绝返回403。这就解释了一个非常普遍的现象本地调试好好的部署到服务器就 403或者用 Postman 能请求用代码就请求不了。本质都是请求头差异。2.3 配额、并发与看起来没超的超限除了来源校验还有一类403来自配额。天地图对每个 tk 有一定的日调用量和并发限制。正常使用一般碰不到上限但以下几种情况会踩爬虫式批量抓瓦片短时间内发起海量请求底图缩放级别开到很大瓦片数量指数级增长多个项目共用同一个 tk总量叠加爆表这类403有个特点一开始是正常的跑着跑着突然大面积失败过一段时间又恢复。如果你遇到的是周期性、间歇性的 403而不是稳定必现的 403那基本可以锁定在配额或者限流上而不是配置错误。排查方法很简单登录控制台看调用量统计。如果发现用量曲线在某个时间点陡然拉高那答案就清楚了。解决办法要么是申请更高配额要么是分散到多个 tk要么是老老实实做瓦片缓存别每次都去实时请求。3. 请求头和Referer为什么浏览器打得开程序就403这一节单独拿出来讲是因为前面提到的浏览器通、程序挂现象实在太典型了值得深挖。理解透了以后再遇到类似的服务校验问题你能举一反三。3.1 浏览器自动带Referer服务端代码默认不带浏览器的行为是贴心的你在页面上发起的任何跨域请求它都会自动把当前页面的地址作为Referer附加上去。而服务端的 HTTP 客户端比如 Java 的HttpURLConnection、HttpClientPython 的requests不带额外设置时默认都不加这个头。所以当天地图服务端看到你的请求没有Referer或者Referer指向的域名和 tk 绑定的域名对不上它就判定这个请求来源不明直接403。我在实际项目里的处理方式是在服务端发起请求时手动把Referer设置成 tk 绑定域名对应的合法地址。比如你的 tk 绑定的是example.com那就把 Referer 设成https://example.com。这样服务端在比对时就能通过校验。3.2 用curl复现最小可复现请求排查这类问题我强烈建议养成用curl复现的习惯。因为curl能把请求头、状态码、响应体一次性打印得清清楚楚比在代码里打日志高效得多。一个典型的天地图瓦片请求长这样curl -v -H Referer: https://example.com \ https://t0.tianditu.gov.cn/vec_w/wmts?SERVICEWMTSREQUESTGetTileVERSION1.0.0LAYERvecSTYLEdefaultTILEMATRIXSETwFORMATtilesTILEMATRIX10TILEROW390TILECOL843tk你的tk加-v之后你就能看到完整的请求头和响应头。如果返回 403可以做个对照实验把Referer头去掉再请求一次。如果去掉之后就 403 了说明服务端确实在校验 Referer如果去掉还能通那说明你的 tk 是服务端类型校验的是 IP问题在别处。这个对照实验能快速帮你定位校验维度。3.3 Nginx反代和云函数里Referer丢失线上环境比本地复杂的地方在于请求往往要经过好几跳客户端 → Nginx → 应用服务器 → 天地图。中间任何一跳都可能把Referer头吃掉或者改掉。常见的两个坑一是Nginx 反向代理默认可能不转发某些头。如果你在 Nginx 里做了转发需要确认proxy_set_header配置里有没有正确处理请求头。二是云函数/Serverless 环境。这类环境的出网 IP 往往是共享的、动态的如果 tk 是服务端类型且绑定了固定 IP那基本没法用。这种情况下要么改用不依赖固定 IP 的校验方式要么走一层有固定出网 IP 的代理。排查这类问题最直接的办法是在应用代码里把实际发出去的请求头完整打出来和curl手工构造的做比对差异一目了然。4. 服务器侧链路排查从出口IP到DNS如果 tk 本身没问题、Referer 也处理了还是 403那就要往更底层查了。这一层的问题相对少见但一旦遇到排查起来最费劲。4.1 出口IP未报备导致的拦截前面提过服务端类型的 tk 通常要绑定服务器公网 IP。这里有个非常容易被忽略的点你绑定的 IP必须是请求真正到达天地图服务器时源站看到的那个 IP。如果服务器直接连公网那出网 IP 就是公网 IP好办。但如果服务器在 NAT 后面、在容器里、或者走了某个网关出口那么天地图看到的源 IP 是网关的 IP而不是你机器上ip addr显示的地址。这时候如果你绑定的是机器地址校验就通不过。验证方法很简单在服务器上执行一条命令去查询我出网时的公网 IP 是什么比如访问一个能回显源 IP 的服务。如果回显出来的 IP 和你绑定的不一致那问题就找到了。解决办法是把这个真实出口 IP 填到 tk 的绑定里。4.2 DNS与HTTPS配置的连带问题天地图的子域名是t0到t7也就是有八个可用的入口。正常使用时会做负载均衡随机或者轮询请求这些子域。有一种情况是部分子域的解析出现问题导致间歇性失败。排查方法是依次对t0到t7逐个ping或者curl看是不是某一个固定失败。如果是可以先临时把请求固定到可用的子域或者检查本机的 DNS 配置。另外天地图同时支持 HTTP 和 HTTPS。如果是在浏览器里加载混用协议比如页面是 HTTPS底图请求用的 HTTP会被浏览器直接拦掉报的还是安全错误和 403 有点像但不完全一样。统一用 HTTPS 能避免一大类问题。4.3 Java HttpClient默认行为踩坑回到具体的代码层面。用 Java 的HttpClientJDK 11 之后的java.net.http.HttpClient请求天地图瓦片时有几个默认行为要注意默认会跟着重定向走但如果目标需要特定头重定向后头可能丢默认对某些响应码的处理比较激进如果自己封装了请求容易漏掉Referer我在项目里封装过一套天地图瓦片下载工具当时踩的坑是用连接池复用了HttpClient结果某些情况下请求头被缓存了导致不同来源的请求复用了同一个错误的 Referer。后来改成每次请求都显式设置头问题就没了。所以建议是不要图省事用全局单例去共享带有来源信息的请求头来源相关的头每次都显式设置。多写几行代码换来的是一劳永逸。排查层级检查项典型现象应用层tk 是否正确、是否过期稳定必现 403应用层Referer / 来源 IP 是否匹配浏览器通、程序挂网络层出口 IP 是否和绑定一致换了环境就挂网络层DNS 解析、子域可用性间歇性失败应用层配额、并发是否超限周期性失败后恢复5. ArcGIS与ArcGIS Pro接入天地图的专属坑用 ArcGIS 或 ArcGIS Pro 这类桌面软件挂天地图在线底图是另一个 403 高发场景。因为软件封装的请求方式和手写代码不一样很多校验细节你看不到只能靠经验判断。5.1 WMTS的URL模板与参数大小写在 ArcGIS Pro 里添加天地图一般走的是 WMTS 服务。URL 模板的拼接非常讲究天地图的参数是大小写敏感的。SERVICE、REQUEST、LAYER这些参数名必须大写值也要按规范来。一个典型可用的 WMTS 地址结构是https://t0.tianditu.gov.cn/vec_w/wmts?SERVICEWMTSREQUESTGetTileVERSION1.0.0LAYERvecSTYLEdefaultTILEMATRIXSETwFORMATtilesTILEMATRIX{level}TILEROW{row}TILECOL{col}tk你的tk注意模板里的占位符{level}、{row}、{col}这是 ArcGIS 识别并替换的变量不同软件的写法略有差异。如果占位符写错请求就会带着字面量{level}发出去自然返回错误。虽然多数时候是 400 或 404但如果服务端做了统一拦截也可能返回 403。5.2 坐标系选错导致的空白与报错vec_w里的w代表Web 墨卡托投影球面墨卡托对应的坐标系是 Web Mercatorvec_c里的c代表地理坐标系经纬度。如果你请求的是vec_w但地图框设的是经纬度坐标系图层要么不显示要么报错。在 ArcGIS Pro 里加载天地图底图后要把地图或图层的坐标系设成和后端服务一致。w系列用 Web Mercatorc系列用地理坐标系。我见过不少人底图怎么都加载不出来最后发现只是坐标系选成了另一个。这个问题的表现不一定是 403但如果服务端配置比较严格也可能统一返回 403。所以排查时别只盯着状态码坐标系也顺手看一眼。5.3 天地图坐标拾取与配准在 ArcGIS Pro 里画要素、做配准时经常需要精确的经纬度坐标。天地图开发资源里提供了坐标拾取工具可以在地图上点选并读出经纬度。用起来比手动换算方便太多。但这里有个大坑天地图公开服务返回的坐标是经过偏移的和标准 GPS 经纬度之间存在系统性差异。如果你把天地图拾取的坐标直接拿去和 GPS 采集的数据叠加会出现整体偏移。反过来也一样。处理方式是在配准或数据叠加前明确坐标系基准做好转换。ArcGIS Pro 里有对应的坐标转换工具选对转换参数很关键。这一步没做好地图看着能显示但位置全偏了比报错还坑因为你不容易发现。注意坐标偏移是地图数据的固有特性不是 bug。做位置叠加前先确认坐标系基准能避免大量返工。6. 一份可以照着走的403自查清单排查403最忌讳东一榔头西一棒子。我把自己长期用的排查思路整理成一条固定路径按顺序走基本不会绕远。6.1 从客户端到服务端的二分排查核心思路是二分定位先用最简单的方式确认问题在哪一层。第一步用curl手工构造请求带上 Referer 和 tk。如果curl通了说明 tk 和绑定没问题问题在你的应用代码或运行环境如果curl也 403说明问题在 tk 或绑定配置本身。第二步如果curl通了而代码不通对比两者的请求头。差异通常在Referer或者请求方法上。第三步如果curl也 403去掉 Referer 再试。去掉后通了说明必须带 Referer去掉后还 403说明校验的是 IP 或 tk 本身有问题。登录控制台核对 tk 状态和绑定信息。第四步确认都正常还是 403那就看上层的配额统计和网络出口 IP。这条路走下来绝大多数403都能定位。我套用这套流程帮别人排查平均半小时内能给出方向剩下的就是改配置。6.2 常见错误对照表最后把我这些年遇到的典型 403 场景和对应解法整理成表方便对照场景根因解决方式浏览器通、代码 403代码没带 Referer显式设置 Referer 头本地通、线上 403服务器出口 IP 和绑定不一致绑定真实出口 IP跑了半天突然 403配额或并发超限申请配额或做瓦片缓存某个模块单独 403该模块用了旧 tk全局替换为最新 tkArcGIS Pro 加载失败URL 参数大小写或占位符错误按官方模板逐字核对底图能显示但位置偏坐标系基准未转换使用坐标转换工具校正间歇性 403部分子域解析异常固定可用子域或检查 DNS说到底天地图的403不是什么玄学它的每一种触发原因都有明确的技术逻辑。你把 tk 校验、Referer、出口 IP、配额这四件事捋顺剩下的基本就是细心问题。我自己现在遇到 403第一反应不再是服务挂了而是打开请求详情看来源信息——这个习惯让我少走了太多弯路。如果你的项目要做瓦片缓存记得把 tk 和 Referer 的配置单独抽出来做成可切换的配置项换环境的时候直接改一处别像我当年那样满代码找密钥。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →