评审会,产品抛来需求:“用户分享位置后,我要在页面上展示’北京市海淀区中关村大街 X 号’,还要能按区统计。” 你的任务:把经纬度变成地址。
这个需求背后就一个接口——逆地址解析 /ws/geocoder/v1/。但"调通"和"上线"之间隔着不少坑:参数顺序、POI 开关、场景策略、授权报错、配额。这篇按天拆完整个流程,哪步会卡、卡在哪,都标出来。结论先说:接口本身半天能调通,但 get_poi、policy 场景、缓存这三件事不提前想,上线前必然返工。
💰 商用授权成本自测:逆地址解析免费额度只用于测试,商用无论调用量多少都要办商业授权(基础版 5 万/年);调用量只影响流量包买多少。文末有免费测算入口。
Day 0:需求拆解
"经纬度变地址"拆成三件事:
关键判断:前两件事是刚需,第三件看业务。只想展示地址 + 按区统计,get_poi 不用开;要"附近有什么"才开。这个判断决定响应体量和流量,Day 3 细说。
Day 1:接口与参数
GET 请求,接口地址:https://apis.map.qq.com/ws/geocoder/v1/
核心参数一张表:
| location | 是 | 坐标,纬度在前、经度在后 | 写反不报错,返回错地址 |
| get_poi | 否 | 是否返回周边 POI:1 返回 / 0 不返回(默认) | 只要地址就保持默认 0 |
| poi_options | 否 | POI 控制,分号分隔 | 见下方场景策略 |
| key | 是 | 开发 Key | 个人 5 个 / 企业 10 个 / 商业 15 个 |
| output | 否 | JSON / JSONP | 默认 JSON |
poi_options 里最值钱的是 policy(返回场景),官方定义了 5 种:
| 1(默认) | 地标+主要道路+近距离 POI | 通用描述 |
| 2 | 到家场景:筛选适合收货的 POI,精确到楼栋 | 电商收货地址 |
| 3 | 出行场景:过滤车辆不易到达的 POI,增加出入口 | 打车/配送 |
| 4 | 社交签到场景 | 位置分享 |
| 5 | 位置共享场景 | 发送位置 |
来源:lbs.qq.com WebService API 文档(逆地址解析)。坐标系为 GCJ-02。
Day 3:联调——三个坑
坑一:location 顺序写反,不报错。
location=39.984154,116.307490 是"纬度,经度"。习惯先写经度的团队,写反了 status 仍是 0,但返回的是几百公里外的地址——比报错难查十倍。
坑二:get_poi 开关决定响应体量。
默认 get_poi=0 返回体量小、速度快。做"展示地址"功能直接保持默认;开着 get_poi=1 又不看 POI,流量白烧。先确认需求再开。
坑三:授权报错(110/111/112)。
联调最常见的是这三条:
| 110 | 请求来源未被授权 | 控制台配域名白名单(Web 端) |
| 111 | 签名验证失败 | 开启了签名校验,检查 SK 与签名逻辑 |
| 112 | IP 未被授权 | 控制台 IP 白名单加当前服务器 IP |
联调通过的最小请求:
// 逆地址解析:坐标 → 地址(Node.js 示例)
const url = 'https://apis.map.qq.com/ws/geocoder/v1/'
+ '?location=39.984154,116.307490' // 纬度在前
+ '&get_poi=0' // 只要地址,不开 POI
+ '&key=YOUR_KEY'
const r = await fetch(url).then(res => res.json())
if (r.status !== 0) throw new Error(`解析失败: ${r.status} ${r.message}`)
console.log(r.result.address) // 完整地址
console.log(r.result.ad_info.adcode) // 行政区划代码,做统计
返回结构里三个字段最常用:result.address(地址)、result.ad_info.adcode(区划代码)、result.formatted_addresses.recommend(更人性化的描述)。
Day 7:上线前——配额与缓存
个人开发者默认 6,000 次/天、5 QPS(逆地址解析)。两个真实约束:
- 5 QPS 会撞并发:前端每次进页面都调一次,人多就超。服务端统一调接口,前端走你的后端。
- 重复调用是最大浪费:同一栋楼、同一个路口反复解析,返回的是同一个地址。按坐标截断 4 位(≈11 米)做缓存键,同区域直接命中缓存,能省掉大部分调用。
// 网格化缓存(生产环境换 Redis + TTL)
const cache = new Map();
const TTL = 7 * 24 * 3600 * 1000;
function gridKey(lat, lng, precision = 4) {
return `${lat.toFixed(precision)},${lng.toFixed(precision)}`;
}
async function reverseGeocode(lat, lng, key) {
const k = gridKey(lat, lng);
const hit = cache.get(k);
if (hit && Date.now() – hit.t < TTL) return hit.v; // 命中不计费
const url = `https://apis.map.qq.com/ws/geocoder/v1/`
+ `?location=${lat},${lng}&key=${key}`;
const res = await fetch(url).then(r => r.json());
if (res.status !== 0) throw new Error(`[${res.status}] ${res.message}`);
cache.set(k, { v: res.result, t: Date.now() });
return res.result;
}
两个配套注意:
- 错误响应不要缓存:status !== 0 时缓存下来,一次偶发失败会变成持续 7 天的故障
- 精度按场景选:展示类 4 位(约 11 米)足够;考勤/计费这类有责任边界的场景不要放宽到 3 位(约 111 米),会跨楼
上线后:监控与维护
- 监控 status 分布:突然出现大量 310/110,先查参数和授权,不是查代码
- 缓存命中率:上线一周后看命中率,低于预期说明缓存键精度太高(点太散)
- 官方文档变更同步:配额、字段可能调整,每月扫一遍
帮你把逆地址解析这笔账算清
逆地址解析是典型的"单次便宜、量大积少成多"接口——授权费(基础版 5 万/年)是固定成本,真正拉开差距的是流量包:缓存命中率每高 10 个点,流量包就省一大截。
你的业务是"展示地址"还是"要 POI/周边推荐"?预估每天多少用户触发?把这两个信息丢评论区,我按官方档位帮你算授权版本 + 流量包预估,包括缓存怎么设计最省。免费,1 个工作日内回。
网硕互联帮助中心






评论前必须登录!
注册