澜湄联盟 · 开放 API 接入文档

版本 2026-07-06 · 接口前缀 /api/open/v1

1. 概述

澜湄联盟官网对外开放数据接口,供第三方系统调用获取联盟相关数据。

当前状态:默认无需鉴权 — 可直接调用下方接口,无需 AppId、签名 Header。 后期如需启用鉴权,服务端配置 open.api.auth-enabled=true 即可。
项目 说明
接口前缀 /api/open/v1/**
Base URL https://your-domain.com(请替换为实际域名)
认证方式 默认关闭;可配置 auth-enabled: true 启用 HMAC 签名
权限控制 鉴权开启后,后台为每个应用勾选 Scope
响应格式 JSON,统一 { code, message, data } 包装

架构示意(鉴权开启时)

第三方系统 │ X-App-Id + X-Sign ▼ OpenApiAuthInterceptor(签名 / 时间戳 / Nonce / 限流 / IP) ▼ @OpenScope 权限校验 ▼ Open Controller ▼ Portal Service(业务数据层)

2. 管理后台使用

鉴权开启后,需在管理后台创建应用并分配权限。入口:系统管理 → 开放接口

2.1 创建应用

  1. 进入 系统管理 → 开放接口
  2. 点击 创建应用,填写应用名称
  3. 勾选 数据权限(Scope)
  4. 保存后弹窗展示 AppIdAppSecret仅展示一次,请立即复制保存

2.2 应用配置项

字段 说明
应用名称 合作方名称,如「XX 旅游平台」
状态 启用 / 禁用
限流/分钟 默认 100 次/分钟
IP 白名单 逗号分隔,留空不限制
过期时间 留空表示永不过期
数据权限 Scope 多选,可随时调整

3. 鉴权开关

当前环境默认 不鉴权,以下签名章节供后期启用时参考。
open:
  api:
    auth-enabled: true   # 或环境变量 OPEN_API_AUTH_ENABLED=true

4. 签名认证(auth-enabled=true 时生效)

4.1 请求 Header

Header 说明
X-App-Id 应用 AppId,如 lm_a1b2c3d4e5f6
X-Timestamp Unix 时间戳(秒),与服务端时差 ≤ 300 秒
X-Nonce 随机字符串,16~32 位,不可重复使用
X-Sign HMAC-SHA256 签名,十六进制小写

4.2 签名算法

signContent = appId + "\n"
            + timestamp + "\n"
            + nonce + "\n"
            + METHOD + "\n"
            + path + "\n"
            + sortedQueryString + "\n"
            + sha256(body)

sign = HMAC-SHA256(appSecret, signContent).toHexLowerCase()
  • path:不含域名,如 /api/open/v1/regions/countries
  • sortedQueryString:Query 参数按 key 字典序,URL 编码后用 & 连接;无参数时为空字符串
  • body:GET 为空字符串的 SHA256;POST/PUT 为 raw body 的 SHA256

5. 接口列表

5.1 快速开始(当前无需鉴权)

直接 GET 请求即可,示例(请将域名替换为实际地址):

GET /api/open/v1/regions/countries?lang=zh-CN
GET /api/open/v1/regions/children?parentId=1&lang=zh-CN
GET /api/open/v1/cms/category?lang=zh-CN
GET /api/open/v1/cms/tag?lang=zh-CN

5.2 连通性测试

GET /api/open/v1/ping

鉴权开启时用于验证 AppId 与签名是否正确。

5.3 地区数据 已开放

鉴权开启时需 Scope:region:read

方法 路径 参数 说明
GET /api/open/v1/regions/countries lang(默认 zh-CN) 六国国家列表(level=1)
GET /api/open/v1/regions/children parentId(必填)、lang 子级地区(省州等)

响应示例 — countries

{
  "code": 200,
  "message": "success",
  "data": [
    { "id": 1, "code": "CN", "name": "中国", "sort": 1 },
    { "id": 2, "code": "TH", "name": "泰国", "sort": 2 }
  ]
}

响应示例 — children

{
  "code": 200,
  "message": "success",
  "data": [
    { "id": 10, "code": "110000", "name": "北京市", "parentId": 1, "level": 2, "sort": 1 }
  ]
}

5.4 CMS 分类 已开放

鉴权开启时需 Scope:cms:category:read

方法 路径 说明
GET /api/open/v1/cms/category 分类树,支持 lang
GET /api/open/v1/cms/category/slug/{slug} 按 slug 获取分类详情 + i18n

字段说明 — category 节点

字段 类型 说明
id number 分类 ID
parentId number 父级 ID,0 表示顶级
slug string URL 标识,可为空
name string 分类名称(按 lang 参数回填,fallback:请求语言 → en → 任意可用语言)
sort number 排序值,升序
status number 状态,1=启用(接口仅返回启用分类)
children array 子分类列表,树形嵌套;无子级时为 []
createTime string 创建时间
updateTime string 更新时间
deleted null 逻辑删除标记,正常数据为 null

响应示例 — category 树(完整数据,lang=zh-CN)

GET /api/open/v1/cms/category?lang=zh-CN

{
  "code": 200,
  "message": "Success",
  "data": [
    {
      "id": 1,
      "deleted": null,
      "createTime": "2026-05-16 09:28:29",
      "updateTime": "2026-07-05 17:06:11",
      "parentId": 0,
      "slug": "news",
      "sort": 0,
      "status": 1,
      "name": "中国文旅",
      "children": []
    },
    {
      "id": 2,
      "deleted": null,
      "createTime": "2026-06-01 17:03:31",
      "updateTime": "2026-07-01 20:45:42",
      "parentId": 0,
      "slug": "other_news",
      "sort": 0,
      "status": 1,
      "name": "国际视野",
      "children": []
    },
    {
      "id": 9,
      "deleted": null,
      "createTime": "2026-07-05 17:06:23",
      "updateTime": "2026-07-05 17:06:23",
      "parentId": 0,
      "slug": "",
      "sort": 0,
      "status": 1,
      "name": "柬埔寨文旅",
      "children": []
    },
    {
      "id": 11,
      "deleted": null,
      "createTime": "2026-07-05 17:06:44",
      "updateTime": "2026-07-05 17:06:44",
      "parentId": 0,
      "slug": "老挝文旅",
      "sort": 0,
      "status": 1,
      "name": "老挝文旅",
      "children": []
    },
    {
      "id": 12,
      "deleted": null,
      "createTime": "2026-07-05 17:06:55",
      "updateTime": "2026-07-05 17:06:55",
      "parentId": 0,
      "slug": "缅甸文旅",
      "sort": 0,
      "status": 1,
      "name": "Category-12",
      "children": []
    },
    {
      "id": 13,
      "deleted": null,
      "createTime": "2026-07-05 17:07:02",
      "updateTime": "2026-07-05 17:07:02",
      "parentId": 0,
      "slug": "泰国文旅",
      "sort": 0,
      "status": 1,
      "name": "Category-13",
      "children": []
    },
    {
      "id": 14,
      "deleted": null,
      "createTime": "2026-07-05 17:07:12",
      "updateTime": "2026-07-05 17:07:12",
      "parentId": 0,
      "slug": "越南文旅",
      "sort": 0,
      "status": 1,
      "name": "Category-14",
      "children": []
    }
  ]
}

5.5 CMS 标签 已开放

鉴权开启时需 Scope:cms:tag:read

方法 路径 说明
GET /api/open/v1/cms/tag 标签列表,支持 lang
GET /api/open/v1/cms/tag/slug/{slug} 按 slug 获取标签详情 + i18n

字段说明 — tag 节点

字段 类型 说明
id number 标签 ID
slug string URL 标识,可为空
name string 标签名称(按 lang 参数回填,fallback:请求语言 → en → 任意可用语言)
sort number 排序值,升序
status number 状态,1=启用(接口仅返回启用标签)
createTime string 创建时间
updateTime string 更新时间
deleted null 逻辑删除标记,正常数据为 null

响应示例 — tag 列表(lang=zh-CN)

GET /api/open/v1/cms/tag?lang=zh-CN

{
  "code": 200,
  "message": "Success",
  "data": [
    {
      "id": 1,
      "deleted": null,
      "createTime": "2026-07-05 10:00:00",
      "updateTime": "2026-07-05 10:00:00",
      "slug": "tag1",
      "sort": 0,
      "status": 1,
      "name": "标签一"
    },
    {
      "id": 2,
      "deleted": null,
      "createTime": "2026-07-05 10:00:00",
      "updateTime": "2026-07-05 10:00:00",
      "slug": "tag2",
      "sort": 1,
      "status": 1,
      "name": "标签二"
    },
    {
      "id": 3,
      "deleted": null,
      "createTime": "2026-07-05 10:00:00",
      "updateTime": "2026-07-05 10:00:00",
      "slug": "policy_updates",
      "sort": 2,
      "status": 1,
      "name": "政策动态"
    }
  ]
}

6. Scope 权限一览(鉴权开启时生效)

Scope 说明 状态
region:read 地区/国家 已开放
cms:category:read CMS 分类 已开放
cms:tag:read CMS 标签 已开放
cms:article:read CMS 文章 待扩展
cms:page:read CMS 单页 待扩展
biz:org:read 商务机构 待扩展
biz:resource:read 商务资源 待扩展
media:read 媒体名录 待扩展
material:read 素材库 待扩展
data:report:read 数据报告 待扩展
product:read 商城商品 待扩展
search:read 统一搜索 待扩展

7. 错误码

Code 说明
200 成功
1400 请求参数错误
1601 应用不存在
1602 应用已禁用
1603 应用已过期
1604 签名无效
1605 时间戳过期
1606 Nonce 重复使用
1607 IP 不在白名单
1608 超出限流
1609 无对应 Scope 权限

8. 代码示例

8.1 直接调用(当前,无需鉴权)

# curl
curl "https://your-domain.com/api/open/v1/regions/countries?lang=zh-CN"

# Python
import requests
r = requests.get("https://your-domain.com/api/open/v1/regions/countries", params={"lang": "zh-CN"})
print(r.json())

8.2 Python 签名示例(鉴权开启时)

import hashlib, hmac, time, uuid, urllib.parse, requests

APP_ID = "lm_xxxxxxxxxxxx"
APP_SECRET = "your-secret-here"
BASE = "https://your-domain.com"

def sha256_hex(s):
    return hashlib.sha256(s.encode("utf-8")).hexdigest()

def build_query(params):
    items = []
    for key in sorted(params.keys()):
        val = params[key]
        if val is None: continue
        items.append(f"{urllib.parse.quote(key, safe='')}={urllib.parse.quote(str(val), safe='')}")
    return "&".join(items)

def sign(method, path, params, body=""):
    ts = str(int(time.time()))
    nonce = uuid.uuid4().hex
    content = "\n".join([APP_ID, ts, nonce, method.upper(), path, build_query(params), sha256_hex(body)])
    sig = hmac.new(APP_SECRET.encode(), content.encode(), hashlib.sha256).hexdigest()
    return ts, nonce, sig

path = "/api/open/v1/regions/countries"
params = {"lang": "zh-CN"}
ts, nonce, sig = sign("GET", path, params)
r = requests.get(BASE + path, params=params, headers={
    "X-App-Id": APP_ID, "X-Timestamp": ts, "X-Nonce": nonce, "X-Sign": sig,
})
print(r.json())

8.3 curl 签名示例(鉴权开启时)

curl -G "https://your-domain.com/api/open/v1/regions/countries" \
  -H "X-App-Id: lm_xxxxxxxxxxxx" \
  -H "X-Timestamp: 1719900000" \
  -H "X-Nonce: abc123def4567890" \
  -H "X-Sign: <computed_hmac>" \
  --data-urlencode "lang=zh-CN"

9. 服务端配置(运维参考)

open:
  api:
    auth-enabled: ${OPEN_API_AUTH_ENABLED:false}
    encrypt-key: ${OPEN_API_ENCRYPT_KEY:lm-open-api-key!}
    timestamp-skew-seconds: 300
    nonce-ttl-seconds: 600