You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Nominatim/OpenStreetMap反向查询返回不可读内容及403错误求助

问题:Nominatim反向地理编码403错误及添加User-Agent后乱码问题

问题背景

通过Nominatim/OpenStreetMap对GPS经纬度执行反向查询获取地址,示例请求URL:

https://nominatim.openstreetmap.org/reverse?lat=50.59865&lon=8.41693&zoom=20&format=json&accept-language=de_DE&addressdetails=1

该请求在浏览器中可正常返回JSON响应,但原JSoup请求代码现在返回403 Forbidden:

Response response=Jsoup
    .connect(url)
    .timeout(20000) 
    .header("Content-Type","application/json; charset=utf-8")
    .header("Accept-Encoding","gzip,deflate,br")
    .method(Method.GET)
    .maxBodySize(0)
    .ignoreContentType(true)
    .execute();

添加userAgent(DEFAULT_UA)后,请求不再返回403,但返回内容乱码,无法识别编码格式。

原因分析

  1. 403 Forbidden原因:Nominatim近期加强了请求校验,缺失或不符合规范的User-Agent会被判定为爬虫/滥用请求,直接拒绝。
  2. 乱码原因:请求头指定了接受gzip/deflate/br压缩编码,但JSoup默认不会自动解压压缩响应,导致读取的是原始压缩二进制数据,表现为乱码。

解决建议

1. 修复403 Forbidden问题

设置符合Nominatim要求的User-Agent,必须明确标识你的应用信息(最好包含联系方式),不要使用模糊的默认UA:

.userAgent("YourAppName/1.0 (your-contact-email@example.com)")

Nominatim要求User-Agent能识别请求来源,便于他们处理潜在的滥用问题,避免账号/IP被封禁。

2. 修复乱码问题

有两种方案可选:

方案一:移除压缩请求头(简单直接)

删除Accept-Encoding头,让服务器返回未压缩的明文响应:

Response response=Jsoup
    .connect(url)
    .timeout(20000) 
    .header("Accept", "application/json") // 替换GET请求不需要的Content-Type为Accept头
    .userAgent("YourAppName/1.0 (your-contact-email@example.com)")
    .method(Method.GET)
    .maxBodySize(0)
    .ignoreContentType(true)
    .execute();

注意:GET请求不需要设置Content-Type头,应设置Accept头指定期望的响应格式,更符合HTTP规范。

方案二:保留压缩并手动解压(节省带宽)

如果需要压缩来减少传输数据,可根据响应的Content-Encoding头手动解压:

Response response = Jsoup.connect(url)
    .timeout(20000)
    .header("Accept", "application/json")
    .header("Accept-Encoding", "gzip,deflate,br")
    .userAgent("YourAppName/1.0 (your-contact-email@example.com)")
    .method(Method.GET)
    .maxBodySize(0)
    .ignoreContentType(true)
    .execute();

String content;
String encoding = response.header("Content-Encoding");
if ("gzip".equals(encoding)) {
    try (GZIPInputStream gzipIn = new GZIPInputStream(response.bodyStream())) {
        content = new String(gzipIn.readAllBytes(), StandardCharsets.UTF_8);
    }
} else if ("deflate".equals(encoding)) {
    try (InflaterInputStream deflateIn = new InflaterInputStream(response.bodyStream())) {
        content = new String(deflateIn.readAllBytes(), StandardCharsets.UTF_8);
    }
} else if ("br".equals(encoding)) {
    // 需要引入Brotli解压依赖,比如org.brotli:decoder
    try (BrotliInputStream brIn = new BrotliInputStream(response.bodyStream())) {
        content = new String(brIn.readAllBytes(), StandardCharsets.UTF_8);
    }
} else {
    content = response.body();
}

额外注意事项

  • 遵守Nominatim使用限制:请求间隔至少1秒,避免批量高频请求,否则可能触发速率限制或被封禁。
  • 不要用于商业大规模数据抓取,如需批量处理,建议部署自己的Nominatim实例。

内容的提问来源于stack exchange,提问作者Ulrich

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 16:24:51