跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

Java 百度地图 SN 权限签名实践:搜索 2.0 接口示例

介绍 Java 开发者如何使用百度地图 SN 权限签名。内容包括 SN 签名原理、开启方法、算法逻辑及 Java 代码实现。重点讲解地点搜索 2.0 接口的参数构造、MD5 加密过程及常见校验失败原因(如字符编码、参数顺序)。提供完整的请求代码示例,帮助开发者安全调用百度地图 API。

技术博主发布于 2026/3/29更新于 2026/9/358 浏览
Java 百度地图 SN 权限签名实践:搜索 2.0 接口示例

SN 签名简介

1、SN 签名是什么

SN 权限签名是一种安全机制,用于验证应用对百度地图 API 的访问请求是否合法。通过为每个请求生成唯一的签名,百度地图能够有效防止未经授权的访问和滥用。

在调用服务时必须要携带 AK 在每次服务调用时进行访问请求。以地点检索服务为例,关键参数如下表所示:

| sn | 开发者的权限签名。sn 校验说明 | string(50) | 可选,若开发者所用 AK 的校验方式为 SN 校验时该参数必须。 | timestamp | 设置 sn 后该值必填。 | string(50) | 设置 sn 后该值必填。

2、如何开启 SN 签名

登录百度地图开发者平台,进入控制台。创建新应用,填写应用名称、应用类型(服务端 AK 不再支持浏览器端使用;浏览器端使用请选择'浏览器端 AK')、启用服务、请求校验方式(默认是使用 IP 限制,这里选择 SN 校验)。

文章配图

点击创建应用后,按要求填写信息并提交。请记住这里的 SK,在后面的签名中还会使用到。

文章配图

文章配图

3、SN 签名算法

计算 sn 跟参数对出现顺序有关,get 请求请使用 LinkedHashMap 保存<key,value>,该方法根据 key 的插入顺序排序;post 请使用 TreeMap 保存<key,value>,该方法会自动将 key 按照字母 a-z 顺序排序。

开发者会根据自己的应用 SK 和 AK,加上请求参数生成一个 SN,然后将请求发送到服务端,如果两者匹配,请求返回,反之会报 APP SN 校验失败。

请求接口是 V2 版本的检索接口,地址如下:

https://api.map.baidu.com/place/v2/search?

请求的参数如下:

String query = "36";
String region = "158"; // 158 表示长沙市
String scope = "2";
String output = ;
   ;
   ;
   ;
"json"
String
ret_coordtype
=
"WGS84"
int
page_size
=
20
int
page_num
=
0

其生成算法如下图:

文章配图

在 Java 中的应用

1、请求 Map 参数化

这里以地点搜索接口为例,首先定义一个数据请求参数 Map,代码如下:

Map<String, String> params = new LinkedHashMap<String, String>();
// 美食餐饮 -- 543c03f1792d66df98709b45b009d67b
String query = "邮政";
String region = "158"; // 158 表示长沙市
String scope = "2";
String output = "json";
String ret_coordtype = "WGS84";
int pageSize = 20;
int pageNum = 0;
params.put("query", query);
params.put("region", region);
params.put("output", output);
params.put("scope", scope);
params.put("ret_coordtype", ret_coordtype);
params.put("page_size", String.valueOf(pageSize));
params.put("page_num", String.valueOf(pageNum));
params.put("ak", AK);

这个 Map 是生成 SN 签名的基础,在后续的认证过程中会持续用到。

2、SN 签名生成

对于 Java 开发者来说,掌握正确的 SN 权限签名方法,不仅可以确保应用能够稳定地调用百度地图服务,还能避免因签名错误导致的频繁接口调用失败。

为了在接口请求中对中文的字符进行转义,因此要求我们首先进行统一编码,将 map 拼接成请求字符串,核心方法如下:

// 对 Map 内所有 value 作 utf8 编码,拼接返回结果
public String toQueryString(Map<?, ?> data) throws UnsupportedEncodingException {
    StringBuffer queryString = new StringBuffer();
    for (Map.Entry<?, ?> pair : data.entrySet()) {
        queryString.append(pair.getKey() + "=");
        // 第一种方式使用的 jdk 自带的转码方式 第二种方式使用的 spring 的转码方法 两种均可
        // queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8").replace("+", "%20") + "&");
        queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8") + "&");
    }
    if (queryString.length() > 0) {
        queryString.deleteCharAt(queryString.length() - 1);
    }
    return queryString.toString();
}

然后拼接请求接口前缀和带上 SK 值,sk 值就是在前面创建应用时获取到的信息。拼接方法较简单,代码如下:

// 对 paramsStr 前面拼接上/geocoder/v2/?,后面直接拼接 yoursk 得到/geocoder/v2/?address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourakyoursk
String wholeStr = new String("/place/v2/search?" + paramsStr + SK);
System.out.println(wholeStr); // 对上面 wholeStr 再作 utf8 编码
String tempStr = URLEncoder.encode(wholeStr, "UTF-8");

最后对调用 MD5 加密生成 SN 值,调用及生成核心方法如下:

// 调用下面的 MD5 方法得到最后的 sn 签名
String sn = snCal.MD5(tempStr);
System.out.println("sn===>" + sn);

生成 MD5 的方法很多,这里分享一种比较简单方法,如下:

// 来自 stackoverflow 的 MD5 计算方法,调用了 MessageDigest 库函数,并把 byte 数组结果转换成 16 进制
public String MD5(String md5) {
    try {
        java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
        byte[] array = md.digest(md5.getBytes());
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < array.length; ++i) {
            sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString();
    } catch (java.security.NoSuchAlgorithmException e) {
    }
    return null;
}

3、搜索接口调用

为了演示实际的搜索方法,这里创建最原生的 Java 请求对象来进行发送网络请求,使用原生的方式创建请求对象及发送请求的核心代码如下:

/**
 * 选择了 ak,使用 SN 校验:根据您选择的 AK 已为您生成调用代码 检测您当前的 AK 设置了 sn 检验,本示例中已为您生成 sn 计算代码
 *
 * @param strUrl
 * @param param
 * @throws Exception
 */
public void requestGetSN(String strUrl, Map<String, String> param) throws Exception {
    if (strUrl == null || strUrl.length() <= 0 || param == null || param.size() <= 0) {
        return;
    }
    StringBuffer queryString = new StringBuffer();
    queryString.append(strUrl);
    for (Map.Entry<?, ?> pair : param.entrySet()) {
        queryString.append(pair.getKey() + "=");
        // 第一种方式使用的 jdk 自带的转码方式 第二种方式使用的 spring 的转码方法 两种均可
        // queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8").replace("+", "%20") + "&");
        queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8") + "&");
    }
    if (queryString.length() > 0) {
        queryString.deleteCharAt(queryString.length() - 1);
    }
    java.net.URL url = new URL(queryString.toString());
    URLConnection httpConnection = (HttpURLConnection) url.openConnection();
    httpConnection.connect();
    InputStreamReader isr = new InputStreamReader(httpConnection.getInputStream());
    BufferedReader reader = new BufferedReader(isr);
    StringBuffer buffer = new StringBuffer();
    String line;
    while ((line = reader.readLine()) != null) {
        buffer.append(line);
    }
    reader.close();
    isr.close();
    System.out.println("SN: " + buffer.toString());
}

在 Main 方法中调用 SN 签名生成以及实际调用的代码如下,首先需要替换您的应用 ak 和 sk 的值,方可运行。

package com.yelang.project.unihttp;
import org.springframework.web.util.UriUtils;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.security.NoSuchAlgorithmException;
import java.util.LinkedHashMap;
import java.util.Map;

public class SearchHttpSN {
    public static String AK = "yourak";
    public static String SK = "yoursk";
    public static String URL = "https://api.map.baidu.com/place/v2/search?";

    public static void main(String[] args) throws Exception {
        SearchHttpSN snCal = new SearchHttpSN();
        Map<String, String> params = new LinkedHashMap<String, String>();
        String query = "邮政";
        String region = "158"; // 158 表示长沙市
        String scope = "2";
        String output = "json";
        String ret_coordtype = "WGS84";
        int pageSize = 20;
        int pageNum = 0;
        params.put("query", query);
        params.put("region", region);
        params.put("output", output);
        params.put("scope", scope);
        params.put("ret_coordtype", ret_coordtype);
        params.put("page_size", String.valueOf(pageSize));
        params.put("page_num", String.valueOf(pageNum));
        params.put("ak", AK);
        params.put("sn", snCal.caculateSn());
        snCal.requestGetSN(URL, params);
    }
}

执行完成后,在控制台看到以下输出表示成功发起了请求,并且返回了数据,表示通过了 SN 验证并且返回了指定数据:

文章配图

APP SN 校验失败可能的原因

在实际开发过程中,Java 开发者在进行百度地图 SN 权限签名时往往会面临诸多挑战。一方面,签名算法本身涉及多个参数的处理和特定的加密规则,稍有不慎就可能导致签名错误;另一方面,不同类型的百度地图 API 接口可能对签名参数的要求存在差异,这进一步增加了开发的复杂性。

1、字符编码问题

API 请求中需要用到中文或一些特殊字符的参数,如 query、region 等,为了避免提交到后台乱码,需要对这几个参数值进行编码处理,转换成 UTF-8 字符的二字符十六进制值,凡是不在下表中的字符都需要进行编码。

字符集合字符
URL 非保留字a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 - _ . ~
URL 保留字! * ' ( ) ; : @ & = + $ , / ? % # [ ]

如果中文参数中使用 URL 保留字字符的字面意思,例如:region 关键字取值为"?北京",检索关键字包含一个问号,此问号也必须进行编码。在上面的内容,我们使用 UTF-8 进行转义,因此很好的避免了由于字符编码问题引起的问题。

2、参数顺序

另一个容易出现的问题就是参数的顺序问题,比如我们随意调整请求参数的顺序,计算出来的 SN 值为:sn==>0d5e1ea029c398ed47ef8cb8a0847eaf,未替换之前的 SN 值为:ba424c6d1f2661e30bcc88a364ee8c6e,此时就会出现:SN: {"status":211,"message":"APP SN 校验失败"}。所以如果碰到 SN 签名不通过的问题,首先应该查看参数的顺序,因为 SN 的签名算法很简单,就是按顺序计算 MD5,因此顺序的改变一定会导致 MD5 值的变化,从而导致服务端加密时不匹配,从而导致请求失败。

3、timestamp 的设置

官方文档中,timestamp 字段在设置了 sn 签名时要求必填,但是在实测过程中,并没有传递该参数,也不影响实际的请求,可能这是官方隐藏的彩蛋吧。

目录

  1. SN 签名简介
  2. 1、SN 签名是什么
  3. 2、如何开启 SN 签名
  4. 3、SN 签名算法
  5. 在 Java 中的应用
  6. 1、请求 Map 参数化
  7. 2、SN 签名生成
  8. 3、搜索接口调用
  9. APP SN 校验失败可能的原因
  10. 1、字符编码问题
  11. 2、参数顺序
  12. 3、timestamp 的设置

更多推荐文章

查看全部
  • 学术写作合规挑战:智能降重与 AIGC 检测应对方案
  • AI 时代脱颖而出的关键:商业认知与行动指南
  • Docker 网络 Bridge 模式详解
  • VS Code 中 GitHub Copilot 无法使用?关键排查与修复步骤
  • 6 款主流 AI 模型评测:国产 Agent 第一梯队是谁?
  • 麒麟 V10 ARM64 环境部署 WebLogic 12c 实战
  • Pico 4XVR 1.10.13 安装与使用指南
  • 从零搭建双模式可视化编程平台:Python 与 ROS2 集成实践
  • OpenClaw 全平台卸载指南:Windows、macOS、Linux、npm、pnpm
  • MCP 插件实战:browser-tools-mcp 接入与配置指南
  • 基于 Python 数据分析瑞幸与星巴克全国门店分布及关联关系
  • Pyenv 指定 Python 版本:灵活对接 Miniconda 环境
  • C++ list 模拟实现:从底层链表到容器封装
  • 通义万相 2.1 文生图技术优势与部署解析
  • K-Nearest Neighbors 算法距离度量选择与数据维度归一化
  • Web 服务与 I/O 模型详解及 Nginx 实战
  • OpenClaw.ai:Agentic AI 时代的 Spring Framework 时刻
  • MCP 实战:利用 Figma AI Bridge 自动生成前端代码
  • 大模型驱动文档图像识别技术革新
  • 基于 STM32 的智能水质检测系统

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online