AECC 能管系统(AECC Service)开放平台接入指南(概览版)。文档首先讲解接口安全鉴权与签名生成机制,随后提供动态电价与设备服务等核心接口的调用示例,并附常见问题解答,帮助开发者快速完成接入。
所有开放接口调用均需通过严格的签名验证,确保通信安全与数据完整性。
联系 AECC 官方获取专属接入凭证:
凭证安全管理建议:
按以下固定规则拼接签名原文,顺序错误将导致验签失败:
详细构造步骤:
步骤 2.1:提取业务参数 从请求体中提取所有业务参数,排除 time 和 sign 字段:
{
"energyMode": "2",
"aiMode": "0",
"customTimes": "00:00,12:00,1000&13:00,15:00,-2000",
"batRatedCapacity": "1",
"batRatedChargingPower": "1000",
"dataTime": "2025-06-26",
"priceCompany": "Germany"
}
步骤 2.2:参数名排序
按 Unicode 编码升序排列参数名:
aiMode, batRatedCapacity, batRatedChargingPower, customTimes, dataTime, energyMode, priceCompany
步骤 2.3:拼接参数字符串 按排序结果拼接为 key=value 格式,用 & 连接:
aiMode=0&batRatedCapacity=1&batRatedChargingPower=1000&customTimes=00:00,12:00,1000&13:00,15:00,-2000&dataTime=2025-06-26&energyMode=2&priceCompany=Germany
步骤 2.4:追加时间戳与密钥 在字符串末尾追加 time 和 key:
aiMode=0&batRatedCapacity=1&batRatedChargingPower=1000&customTimes=00:00,12:00,1000&13:00,15:00,-2000&dataTime=2025-06-26&energyMode=2&priceCompany=Germany&time=1732756652&key=2a1891544dbcf8e8b45b36d03187485a
注意事项:
使用标准 MD5 算法对拼接完成的待签名字符串进行哈希运算,输出结果必须转换为 全小写 字符串,作为 sign 参数值。
多语言签名示例:
Java 示例:
import java.security.MessageDigest;
import java.util.TreeMap;
public class SignGenerator {
public static String generateSign(TreeMap<String, String> params, String key) {
try {
// 参数已排序(TreeMap自动排序)
StringBuilder sb = new StringBuilder();
// 拼接业务参数
for (String paramKey : params.keySet()) {
if (!paramKey.equals("sign")) { // 排除sign字段
sb.append(paramKey).append("=").append(params.get(paramKey)).append("&");
}
}
// 追加time和key
sb.append("time=").append(params.get("time")).append("&key=").append(key);
// MD5加密并转小写
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(sb.toString().getBytes("UTF-8"));
StringBuilder hexString = new StringBuilder();
for (byte b : digest) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString().toLowerCase();
} catch (Exception e) {
throw new RuntimeException("签名生成失败", e);
}
}
}
Python 示例:
import hashlib
from urllib.parse import urlencode
def generate_sign(params, key):
"""
生成API签名
:param params: 业务参数字典(包含time)
:param key: 分配的密钥
:return: MD5签名字符串(小写)
"""
# 排除sign字段,按key排序
sorted_params = sorted([(k, v) for k, v in params.items() if k != 'sign'])
# 拼接参数
param_str = '&'.join([f"{k}={v}" for k, v in sorted_params])
# 追加time和key
sign_str = f"{param_str}&time={params['time']}&key={key}"
# MD5加密并转小写
return hashlib.md5(sign_str.encode('utf-8')).hexdigest().lower()
# 使用示例
params = {
'energyMode': '2',
'aiMode': '0',
'customTimes': '00:00,12:00,1000&13:00,15:00,-2000',
'batRatedCapacity': '1',
'batRatedChargingPower': '1000',
'dataTime': '2025-06-26',
'priceCompany': 'Germany',
'time': '1732756652'
}
sign = generate_sign(params, '2a1891544dbcf8e8b45b36d03187485a')
print(f"生成的签名: {sign}")
JavaScript 实现:
const crypto = require('crypto');
/**
* 生成API签名
* @param {Object} params - 业务参数对象(包含time)
* @param {string} key - 分配的密钥
* @returns {string} MD5签名字符串(小写)
*/
function generateSign(params, key) {
// 获取排序后的参数键(排除sign)
const sortedKeys = Object.keys(params)
.filter(k => k !== 'sign')
.sort();
// 拼接参数字符串
const paramString = sortedKeys
.map(k => `${k}=${params[k]}`)
.join('&');
// 追加time和key
const signString = `${paramString}&time=${params.time}&key=${key}`;
// MD5加密并转小写
return crypto.createHash('md5')
.update(signString, 'utf8')
.digest('hex')
.toLowerCase();
}
// 使用示例
const params = {
energyMode: '2',
aiMode: '0',
customTimes: '00:00,12:00,1000&13:00,15:00,-2000',
batRatedCapacity: '1',
batRatedChargingPower: '1000',
dataTime: '2025-06-26',
priceCompany: 'Germany',
time: '1732756652'
};
const sign = generateSign(params, '2a1891544dbcf8e8b45b36d03187485a');
console.log('生成的签名:', sign);
C# 实现:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
public class SignGenerator
{
public static string GenerateSign(Dictionary<string, string> parameters, string key)
{
// 排除sign字段,按key排序
var sortedParams = parameters
.Where(p => p.Key != "sign")
.OrderBy(p => p.Key, StringComparer.Ordinal)
.Select(p => $"{p.Key}={p.Value}");
// 拼接参数
string paramString = string.Join("&", sortedParams);
// 追加time和key
string signString = $"{paramString}&time={parameters["time"]}&key={key}";
// MD5加密并转小写
using (var md5 = MD5.Create())
{
byte[] hashBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(signString));
StringBuilder sb = new StringBuilder();
foreach (byte b in hashBytes)
{
sb.Append(b.ToString("x2")); // 转小写十六进制
}
return sb.ToString();
}
}
}
完整请求示例(cURL):
curl --location 'https://api.aecc.com/openApi/price/setEnergyMode' \
--header 'companyCode: AECC2024001' \
--header 'Accept-Language: en-US' \
--header 'Content-Type: application/json' \
--data '{
"energyMode": "2",
"aiMode": "0",
"customTimes": "00:00,12:00,1000&13:00,15:00,-2000",
"batRatedCapacity": "1",
"batRatedChargingPower": "1000",
"dataTime": "2025-06-26",
"priceCompany": "Germany",
"time": "1732756652",
"sign": "c3757db87150d5efbb45009d9253d375"
}'
完整请求示例(Java - HttpClient):
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class ApiClient {
private static final String API_URL = "https://api.aecc.com/openApi/price/setEnergyMode";
private static final String COMPANY_CODE = "AECC2024001";
private static final String KEY = "2a1891544dbcf8e8b45b36d03187485a";
public static void main(String[] args) throws Exception {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(API_URL);
// 设置请求头
httpPost.setHeader("companyCode", COMPANY_CODE);
httpPost.setHeader("Accept-Language", "en-US");
httpPost.setHeader("Content-Type", "application/json");
// 准备业务参数
long currentTime = System.currentTimeMillis() / 1000; // UTC+0秒级时间戳
TreeMap<String, String> params = new TreeMap<>();
params.put("energyMode", "2");
params.put("aiMode", "0");
params.put("customTimes", "00:00,12:00,1000&13:00,15:00,-2000");
params.put("batRatedCapacity", "1");
params.put("batRatedChargingPower", "1000");
params.put("dataTime", "2025-06-26");
params.put("priceCompany", "Germany");
params.put("time", String.valueOf(currentTime));
// 生成签名
String sign = SignGenerator.generateSign(params, KEY);
params.put("sign", sign);
// 构造JSON请求体
JSONObject requestBody = new JSONObject();
for (String key : params.keySet()) {
requestBody.put(key, params.get(key));
}
httpPost.setEntity(new StringEntity(requestBody.toString(), "UTF-8"));
// 发送请求
String response = httpClient.execute(httpPost, response -> {
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity());
System.out.println("响应状态码: " + statusCode);
return responseBody;
});
System.out.println("响应内容: " + response);
httpClient.close();
}
}
服务端验签流程:
服务端按以下步骤验证请求合法性:
身份校验:根据请求头中的 companyCode 查询对应的企业密钥
⚠️ 安全须知:
以下按「动态电价」与「设备服务」两类接口提供核心调用示例,覆盖签名生成、请求构造与响应解析全流程。
动态电价接口地址前缀为 POST /openApi/price/,包含设置能源模式、获取电价区域列表、查询电价、获取电价策略时间段 4 个接口。此类接口为纯服务端计算接口,不涉及具体设备:Body 无需传 deviceSn,由「业务参数 + time + sign」组成,业务参数随接口不同(如 priceCompany、dataTime、energyMode 等),参数值均为 JSON 字符串。请求头与设备接口一致(companyCode、Content-Type: application/json 必选)。
该接口用于配置储能设备的运行模式(智能/自定义/关闭),并获取下发至采集器的加密控制报文。
请求体示例:
{
"energyMode": "2",
"aiMode": "0",
"customTimes": "00:00,12:00,1000&13:00,15:00,-2000",
"batRatedCapacity": "1",
"batRatedChargingPower": "1000",
"dataTime": "2025-06-26",
"priceCompany": "Germany",
"time": "1732756652",
"sign": "c3757db87150d5efbb45009d9253d375"
}
| 名称 | 位置 | 类型 | 必选 | 中文名 | 说明 |
|---|---|---|---|---|---|
| companyCode | header | string | 是 | 唯一码 | AECC 分配的调用方识别码,缺失时返回 result=10001 |
| Content-Type | header | string | 是 | 固定为 application/json | |
| Accept-Language | header | string | 否 | 提示语言(如 en-US、zh-CN),只影响 msg,不影响 result 与业务字段 | |
| body | body | object | 是 | 业务参数 + time + sign,参数值均为 JSON 字符串 | |
| time | body | string | 是 | 秒级时间戳(UTC+0) | 10 位数字字符串,与服务器时间差须小于 3600 秒 |
| sign | body | string | 是 | 签名信息 | 32 位小写 MD5 签名,每次请求重新计算 |
| priceCompany | body | string | 是 | 电价区域 | 德国="Germany" |
| batRatedCapacity | body | string | 是 | 电池额定充满电量(kWh) | 0~100 充满需要消耗的能量 |
| batRatedChargingPower | body | string | 是 | 电池额定充电功率(W) | 根据电池充电功率和容量计算充电时间来选择最低波谷时间 |
| dataTime | body | string | 是 | 当天日期 | yyyy-MM-dd |
| energyMode | body | int | 是 | 能源模式 | 0:无模式,采集器不会对设备进行调控;1:智能模式;2:自定义模式 |
| aiMode | body | int | 否 | AI调控使能 | 0:关闭 1:开启,选择智能模式可设置此值,不传默认关闭。 |
| customTimes | body | string | 否 | 自定义时间段 | 用户自定义设置的充放电时间段,多个时间段使用&隔开,最多16个,格式如:00:00,12:00,1000&13:00,15:00,-2000 |
| baseDischargePower | body | int | 否 | 基础放电功率 |
关键响应字段:
该接口用于获取指定区域、指定日期的分时电价信息,为智能调控策略提供数据支撑。
请求体示例:
{
"dataTime": "2024-09-07",
"priceCompany": "Germany",
"mode": "0",
"time": "1725677116",
"sign": "e07b26034722d166e7f059cb728ab3fd"
}
| 名称 | 位置 | 类型 | 必选 | 中文名 | 说明 |
|---|---|---|---|---|---|
| companyCode | header | string | 是 | 唯一码 | AECC 分配的调用方识别码,缺失时返回 result=10001 |
| Content-Type | header | string | 是 | 固定为 application/json | |
| Accept-Language | header | string | 否 | 提示语言(如 en-US、zh-CN),只影响 msg,不影响 result 与业务字段 | |
| body | body | object | 是 | 业务参数 + time + sign,参数值均为 JSON 字符串 | |
| dataTime | body | string | 是 | 日期 | yyyy-MM-dd |
| priceCompany | body | string | 是 | 电价区域 | 如 Germany |
| mode | body | string | 否 | 电价颗粒度 | 0: 1小时 1: 15分钟 默认0 |
| time | body | string | 是 | 秒级时间戳(UTC+0) | 10 位数字字符串,与服务器时间差须小于 3600 秒 |
| sign | body | string | 是 | 签名信息 | 32 位小写 MD5 签名,每次请求重新计算 |
关键响应字段:
设备接口地址前缀为 POST /openApi/device/。与电价接口不同,设备接口围绕具体设备展开:只需传递 deviceSn,不需要传设备型号代码(DTC),服务端根据授权的 deviceSn 自动路由并返回对应型号结构;查询接口 Body 只有 deviceSn + time + sign。查询接口(示例三、示例四,以及 getSetInfo)不要求设备在线;设置接口(示例五、示例六)要求设备在线,离线返回 result=20008。
本期开放 7 个电表型号,型号与设置的对应关系如下:
| 型号 | 型号代码(DTC) | setParam / setCustomParams |
|---|---|---|
| 智能无线三相CT电表(单路) | 10002 / 65296 / 65348 | 支持 currentReverseSet |
| 智能电表-导轨采集器 WiFi+BLE | 65389 | 支持 6 个极性调整字段 |
| RS06、RS07、RS02、RC01、RS09 | 60675 / 65417 / 88801 | 不支持设置:在线返回 result=1 与设备不支持,离线先返回 result=20008 |
电表各型号字段概要:
| 型号 | 额定信息(getBasicsInfo) | 实时信息(getRealTimeInfo) |
|---|---|---|
| 智能无线三相CT电表(单路) | lineType、currentReverseSet、ctType | ctVersion、三相电压/电流、有功/无功/视在功率、功率因数、频率、正反向电量、负载识别等 36 字段(功率因数字段首字母小写,如 aphasePowerFactor) |
| RS07 | 双路三相额定/设置实体:485通讯地址、两路电流反向/互感器相序/CT变比共 13 字段 | 双路三相实时实体:两路 L1/L2/L3 电压、电流、功率、相位角、电能等 114 字段,另含 openDatalogVo 电表模块属性对象 |
| RS06 | 无独立额定实体,返回 deviceVo=null | RS06 实时实体:三相电压/电流/有功功率、分相电能、功率因数、故障代码、总电网/买/卖电量等 22 字段 |
| RS02 / RC01 / RS09 | 业务字段全空的外部接入电表实体,额定以实时接口为准 | 外部接入电表实时实体:thirdPartyType、功率/电压/电流/频率、ctTotalUseEnergy 等 20 字段 |
| 智能电表-导轨采集器 WiFi+BLE | ctType 与两路互感器极性/相序 17 字段 | 第一路/第二路(后缀 1/2)电压、电流、功率、电能全量字段 |
各型号完整字段表见《AECC能管系统SDK-完整版》设备服务章节。
空业务数据:设备绑定关系存在但数据尚未上报时,接口可能返回 result=0 且 obj.deviceVo=null(obj.deviceSn、obj.dataLogSn 也可能为 null),属正常情况。处理顺序:先判断 result=0,再判断 obj 与 obj.deviceVo 是否为 null,最后读取业务字段。字段顺序不作为契约,必须按字段名解析 JSON。
该接口用于获取当前设备额定参数数据。
请求体示例:
{
"deviceSn": "NB2548300T110CHAB",
"time": "1725450897",
"sign": "e83ba9c021edd831ae69033f77528ac5"
}
| 名称 | 位置 | 类型 | 必选 | 中文名 | 说明 |
|---|---|---|---|---|---|
| companyCode | header | string | 是 | 唯一码 | AECC 分配的调用方识别码,缺失时返回 result=10001 |
| Content-Type | header | string | 是 | 固定为 application/json | |
| Accept-Language | header | string | 否 | 提示语言(如 en-US、zh-CN),只影响 msg,不影响 result 与业务字段 | |
| body | body | object | 是 | 只包含以下业务参数,参数值均为 JSON 字符串 | |
| deviceSn | body | string | 是 | 设备序列号 | 无需传设备类型或数据组编号,服务端按绑定的数据实体自动路由 |
| time | body | string | 是 | 秒级时间戳(UTC+0) | 10 位数字字符串,与服务器时间差须小于 3600 秒 |
| sign | body | string | 是 | 签名信息 | 32 位小写 MD5 签名,每次请求重新计算 |
返回示例(逆变器设备,节选):
{
"result": 0,
"msg": "Request successfully.",
"obj": {
"deviceSn": "NB2548300T110CHAB",
"dataLogSn": "AECCAA0437",
"deviceState": 1,
"deviceVo": {
"serialNumber": "NB2548300T110CHAB",
"ratedPower": 110.0,
"mpptCount": 9,
"stringCount": 18,
"pvStartVoltage": 180.0,
"gridVoltageType": 1,
"mainSDPVersion": "V1.2.3"
}
},
"data": null,
"taskResult": null
}
返回示例(电表设备,单路三相电表实体):
{
"result": 0,
"msg": "请求成功!",
"obj": {
"deviceSn": "EXAMPLE-METER-SN",
"dataLogSn": "EXAMPLE-DATALOG-SN",
"deviceState": 0,
"deviceVo": {
"lineType": 1,
"currentReverseSet": 0,
"ctType": 23
}
},
"data": null,
"taskResult": null
}
该接口用于获取当前设备实时信息数据。
请求体示例:
{
"deviceSn": "NB2548300T110CHAB",
"time": "1725450897",
"sign": "e83ba9c021edd831ae69033f77528ac5"
}
| 名称 | 位置 | 类型 | 必选 | 中文名 | 说明 |
|---|---|---|---|---|---|
| companyCode | header | string | 是 | 唯一码 | AECC 分配的调用方识别码,缺失时返回 result=10001 |
| Content-Type | header | string | 是 | 固定为 application/json | |
| Accept-Language | header | string | 否 | 提示语言(如 en-US、zh-CN),只影响 msg,不影响 result 与业务字段 | |
| body | body | object | 是 | 只包含以下业务参数,参数值均为 JSON 字符串 | |
| deviceSn | body | string | 是 | 设备序列号 | 无需传设备类型或数据组编号,服务端按绑定的数据实体自动路由 |
| time | body | string | 是 | 秒级时间戳(UTC+0) | 10 位数字字符串,与服务器时间差须小于 3600 秒 |
| sign | body | string | 是 | 签名信息 | 32 位小写 MD5 签名,每次请求重新计算 |
返回示例(逆变器设备,节选):
{
"result": 0,
"msg": "Request successfully.",
"obj": {
"deviceSn": "NB2548300T110CHAB",
"dataLogSn": "AECCAA0437",
"deviceState": 1,
"deviceVo": {
"runStatus": 1,
"pvTotalPower": 0.0,
"dailyPvGenEnergy": 717.2,
"totalPvGenEnergy": 29884.8,
"dailyGridConnectGenEnergy": 678.9,
"totalGridConnectGenEnergy": 28431.2,
"gridTotalActivePower": null
}
},
"data": null,
"taskResult": null
}
返回示例(电表设备,单路三相电表实体):
{
"result": 0,
"msg": "请求成功!",
"obj": {
"deviceSn": "EXAMPLE-METER-SN",
"dataLogSn": "EXAMPLE-DATALOG-SN",
"deviceState": 0,
"deviceVo": {
"ctAPhaseVoltage": 220.1,
"ctBPhaseVoltage": 220.2,
"ctCPhaseVoltage": 220.3,
"ctAPhaseCurrent": 10.1,
"ctBPhaseCurrent": 10.2,
"ctCPhaseCurrent": 10.3,
"ctThreePhaseTotalPower": 3000.6,
"aphasePowerFactor": 0.99,
"totalPowerFactor": 0.98,
"frequency": 50.01,
"forwardActiveEnergy": 123.45,
"reverseActiveEnergy": 1.23,
"totalActiveEnergy": 124.68,
"ctType": 23
}
},
"data": null,
"taskResult": null
}
该接口用于设置设备的单个参数。设置前可通过 getSetInfo(POST /openApi/device/getSetInfo,请求与示例三完全一致,仅 URL 不同)查询当前可设置项及其服务端值。
请求示例(逆变器设备):
{
"deviceSn": "NB2548300T110CHAB",
"paramName": "pvStartVoltage",
"paramValue": "179",
"time": "1785461710",
"sign": "<md5-sign>"
}
返回示例(逆变器设备,obj 回显本次设置):
{
"result": 0,
"msg": "Setting successful.",
"obj": {
"pvStartVoltage": "179"
},
"data": null,
"taskResult": null
}
请求示例(电表设备,智能无线三相CT电表·单路):
{
"deviceSn": "<your-deviceSn>",
"paramName": "currentReverseSet",
"paramValue": "1",
"time": "<utc-second-time>",
"sign": "<md5-sign>"
}
返回示例(电表设备,obj 为 null):
{
"result": 0,
"msg": "设置成功!",
"obj": null,
"data": null,
"taskResult": null
}
关键规则:
该接口用于一次设置设备的多个参数,object 为序列化后的 JSON 字符串(不是嵌套 JSON 对象),其值必须与参与签名的字符串逐字符一致,签名后不能再重新格式化或调整内部字段顺序。
请求示例(逆变器设备):
{
"deviceSn": "NB2548300T110CHAB",
"object": "{\"underVoltProtectRecoverValue\":\"197\",\"overVoltProtectRecoverValue\":\"250\"}",
"time": "1785462195",
"sign": "<md5-sign>"
}
返回示例(逆变器设备,obj 回显本次设置):
{
"result": 0,
"msg": "Setting successful.",
"obj": {
"underVoltProtectRecoverValue": "197",
"overVoltProtectRecoverValue": "250"
},
"data": null,
"taskResult": null
}
请求示例(电表设备,智能无线三相CT电表·单路):
{
"deviceSn": "<your-deviceSn>",
"object": "{\"currentReverseSet\":\"1\"}",
"time": "<utc-second-time>",
"sign": "<md5-sign>"
}
请求示例(电表设备,导轨采集器同路多字段):
{
"deviceSn": "<your-deviceSn>",
"object": "{\"transformerPolarityAdjustA1\":\"1\",\"transformerPolarityAdjustB1\":\"0\",\"transformerPolarityAdjustC1\":\"1\"}",
"time": "<utc-second-time>",
"sign": "<md5-sign>"
}
关键规则:
服务端在收到请求后会按相同规则(业务参数按 Unicode 升序拼接 → 末尾追加 time 和 key → MD5 → 转小写)重算签名,并与请求体中的 sign 做精确比较(区分大小写、不做 trim)。任一环节不一致都会判定为签名异常,统一返回 result=10001, msg="Signature exception"。
注意:签名异常、时间戳过期、companyCode/time/sign 缺失在服务端会合并为同一个 10001 错误,无法仅凭 code 区分,需按以下步骤逐项排查。
排查步骤(按命中率从高到低):
// 正确:Spring DigestUtils 返回的就是 32 位小写
String sign = DigestUtils.md5DigestAsHex(text.getBytes(StandardCharsets.UTF_8));
确认参数拼接顺序与原文一致
业务参数名必须按 Unicode(字典序)升序 排列,建议直接用 TreeMap(Java)/ sorted()(Python)/ .sort()(JS)自动排序。拼出来的字符串应为 k1=v1&k2=v2&...&time=xxx&key=xxx。
服务端签名重算核心逻辑(参考实现):
// 1. 业务参数按 TreeMap 字典序拼接(排除 sign 和 time)
// 2. 末尾追加 &time={time}&key={keySecret}
// 3. MD5(text.getBytes("UTF-8")),结果为 32 位小写 hex
if (md5.equals(requestSign)) { /* 通过 */ }
时间偏差处理建议:
不可以。 key(密钥)严禁以任何形式出现在网络请求中。
正确做法:
开放接口的 HTTP 层基本固定返回 200,业务结果通过响应体的 result 字段表达;真正的系统级异常会统一映射为 result=4000, msg="System error, please contact the administrator!"。建议按以下策略处理:
1. 客户端超时设置
建议为每次调用设置合理的连接和读取超时(如连接 5s、读取 10s),避免因网络抖动导致线程长时间阻塞:
// HttpClient 示例
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(5000) // 连接超时 5s
.setSocketTimeout(10000) // 读取超时 10s
.build();
HttpPost httpPost = new HttpPost(url);
httpPost.setConfig(config);
2. 针对 result=4000(系统错误)的重试
3. 针对网络超时(无响应)的处理
4. 不要重试的情况
5. 限流
部分接口配置了接口请求限流。触发限流时会通过全局异常返回错误信息,客户端应降低调用频率,不要立即重试。
说明:响应体中的状态字段实际命名为 result(而非 code),下文为便于理解统一按"状态码"描述。
响应结构:
{
"result": 0,
"msg": "Request successfully.",
"data": { /* 业务数据 */ }
}
常见状态码对照表:
| result | 含义 | 典型 msg(en-US) | 触发场景 |
|---|---|---|---|
| 0 | 成功 | Request successfully. | 业务正常处理完成 |
| 1 | 通用失败 | (由调用方传入) | 业务逻辑校验未通过,msg 会具体说明;或 companyCode 未开放所调用接口的 URL 权限;电表设置时参数名不支持、参数值非 0/1、object 为空或非法、导轨采集器同时传入两路极性调整字段、RS06/RS07/RS02/RC01/RS09 不支持设置、设置超时/失败 |
| 10000 | 未登录/Token 失效 | Please login. / token expired | Token 模式下 claims 无效或过期 |
| 10001 | 签名异常 | Signature exception | 签名错误、时间戳过期、companyCode/time/sign 缺失(合并码,无法细分) |
| 10002 | 邮箱格式错误 | Incorrect email format. | 注册/绑定邮箱格式不合法 |
| 10006 | 用户被禁用 | The user has been disabled. | 账号被锁定 |
| 20000 | 参数类型有误 | Incorrect parameter type. | 请求参数类型不匹配 |
| 20001 | 数据不能为空 | Submitted data cannot be empty. | 必填参数缺失;或业务数据不存在(如电表设置数据行不存在) |
| 20002 | 权限异常 | Abnormal permissions. | openApi 鉴权链路专用:companyCode 在系统中不存在、对应凭证未启用(flagState != 1)、或无操作权限 |
| 20003 | 时间格式错误 | Time format error. | 日期/时间参数格式不合法 |
| 20004 | 参数格式错误 | Parameter format error. | 参数格式校验未通过 |
| 20005 | 无此参数 | No this parameter. | 缺少必要的业务参数 |
| 20006 | 系统错误 | System error, try later. | 服务端业务异常 |
| 20007 | DTC 不存在 | DeviceCode does not exist | 设备类型编码无效;或设备绑定类型没有开放平台实现 |
| 20008 | 设备离线 | Device off-line | 设备未上报数据;设置接口要求设备在线,离线返回此码 |
| 20009 | 设备不存在 | Device not exist | deviceSn 在系统中查不到 |
| 4000 | 系统全局错误 | System error, please contact the administrator! | 未捕获异常、事务回滚、参数解析异常等(建议重试或联系官方) |
排查建议: