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

版本 2026-08-05 · 接口前缀 /api/open/v1

1. 概述

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

当前状态:默认无需鉴权 — 可直接调用下方接口,无需 AppId、签名 Header。 后期如需启用鉴权,服务端配置 open.api.auth-enabled=true 即可。
项目 说明
接口前缀 /api/open/v1/**
Base URL https://lm.linkco.yoois.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": "政策动态"
    }
  ]
}

5.6 CMS 文章推送 已开放

允许外部第三方平台通过 Open API 将文章推送到澜湄联盟平台,支持创建和更新操作。

鉴权开启时需 Scope:cms:article:write

鉴权开启后,所有推送接口均要求 Scope cms:article:write 创建成功后会返回平台生成的文章 id,请务必保存,后续更新需要用它。
方法 路径 说明
GET /api/open/v1/cms/article/{id} 获取文章详情(主表 + 全语言 i18n + 标签)
POST /api/open/v1/cms/article 推送/创建文章
PUT /api/open/v1/cms/article/{id} 更新文章(部分更新,仅覆盖传入字段;i18n 按语言增量更新)
DELETE /api/open/v1/cms/article/{id} 撤稿(逻辑删除,级联清理 i18n 与 tag 关联)

请求参数(JSON Body)

下表字段同时适用于创建更新接口。创建时 categoryIdi18n 为必填;更新时为部分更新,所有字段均可选,仅传入字段被覆盖。

字段 类型 必填 说明
categoryId Long 创建:是 / 更新:否 平台分类 ID(必须存在且 status=1)
coverImg String 封面图 URL
isRecommend Integer 是否推荐,默认 0
isTop Integer 是否置顶,默认 0
sort Long 排序值,默认 0(取值范围较 Integer 更大)
status Integer 发布状态:1=直接发布,0=草稿,默认 1
publishTime String 发布时间(格式 yyyy-MM-dd HH:mm:ss),默认当前时间
tagIds List<Long> 标签 ID 列表(必须存在且 status=1)
i18n List<I18n> 创建:是 / 更新:否 多语言内容。更新时仅传需修改的语言条目(按 lang 增量更新),未传入语言保持不变;新增语言时该条目的 title 必填

I18n 子对象

字段 类型 必填 说明
lang String 语言代码(如 zh-CN, en, th, vi, my, lo, km)
title String 标题
subtitle String 副标题
summary String 摘要
content String 正文 HTML 内容
author String 作者
source String 来源平台名称
seoTitle String SEO 标题
seoKeywords String SEO 关键词
seoDescription String SEO 描述

请求示例 — 推送文章

POST /api/open/v1/cms/article
Content-Type: application/json

{
  "categoryId": 1,
  "coverImg": "https://example.com/cover.jpg",
  "isRecommend": 0,
  "isTop": 0,
  "sort": 0,
  "status": 1,
  "publishTime": "2026-08-05 10:00:00",
  "tagIds": [1, 2],
  "i18n": [
    {
      "lang": "zh-CN",
      "title": "澜湄合作新进展",
      "subtitle": "多国共同推进区域互联互通",
      "summary": "近日,澜湄合作机制迎来新进展...",
      "content": "<p>详细正文内容...</p>",
      "author": "联盟秘书处",
      "source": "合作伙伴平台A",
      "seoTitle": "澜湄合作新进展 - 官网",
      "seoKeywords": "澜湄,合作,区域互联",
      "seoDescription": "澜湄合作机制最新进展报告"
    },
    {
      "lang": "en",
      "title": "New Progress in Lancang-Mekong Cooperation",
      "subtitle": "Countries Jointly Promote Regional Connectivity",
      "summary": "Recently, the LMC mechanism has made new progress...",
      "content": "<p>Detailed content...</p>",
      "author": "LMC Secretariat",
      "source": "Partner Platform A"
    }
  ]
}

成功响应示例

{
  "code": 200,
  "message": "success",
  "data": {
    "article": {
      "id": 123,
      "categoryId": 1,
      "coverImg": "https://example.com/cover.jpg",
      "isRecommend": 0,
      "isTop": 0,
      "sort": 0,
      "status": 1,
      "publishTime": "2026-08-05 10:00:00",
      "viewCount": 0,
      "createTime": "2026-08-05 10:00:00",
      "updateTime": "2026-08-05 10:00:00"
    },
    "i18n": [
      {
        "id": 456,
        "articleId": 123,
        "lang": "zh-CN",
        "title": "澜湄合作新进展",
        "subtitle": "多国共同推进区域互联互通",
        "summary": "近日,澜湄合作机制迎来新进展...",
        "content": "<p>详细正文内容...</p>",
        "author": "联盟秘书处",
        "source": "合作伙伴平台A",
        "seoTitle": "澜湄合作新进展 - 官网",
        "seoKeywords": "澜湄,合作,区域互联",
        "seoDescription": "澜湄合作机制最新进展报告",
        "createTime": "2026-08-05 10:00:00",
        "updateTime": "2026-08-05 10:00:00"
      },
      {
        "id": 457,
        "articleId": 123,
        "lang": "en",
        "title": "New Progress in Lancang-Mekong Cooperation",
        "subtitle": "Countries Jointly Promote Regional Connectivity",
        "summary": "Recently, the LMC mechanism has made new progress...",
        "content": "<p>Detailed content...</p>",
        "author": "LMC Secretariat",
        "source": "Partner Platform A",
        "seoTitle": "",
        "seoKeywords": "",
        "seoDescription": "",
        "createTime": "2026-08-05 10:00:00",
        "updateTime": "2026-08-05 10:00:00"
      }
    ]
  }
}

获取文章详情

GET /api/open/v1/cms/article/{id}

路径参数id — 平台生成的文章 ID。

Query 参数lang(可选,默认 en)— 仅用于标签名称的回退语言;文章正文与标题始终返回全部语言版本。

返回该文章的完整信息:article 主表记录、i18n 该文章所有语言版本列表、tags 标签列表(含 tagId 与按 lang fallback 解析出的 name)。

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

# 成功
{
    "code": 200,
    "message": "Success",
    "data": {
        "article": {
            "id": 73,
            "deleted": null,
            "createTime": "2026-08-12 10:00:58",
            "updateTime": "2026-08-12 10:00:58",
            "categoryId": 1,
            "coverImg": "https://example.com/cover.jpg",
            "isRecommend": 0,
            "isTop": 0,
            "viewCount": 0,
            "sort": 0,
            "status": 0,
            "publishTime": "2026-08-05 10:00:00",
            "title": null,
            "subtitle": null,
            "summary": null,
            "author": null,
            "source": null,
            "categoryName": null
        },
        "i18n": [
            {
                "id": 155,
                "createTime": "2026-08-12 10:00:58",
                "updateTime": "2026-08-12 10:00:58",
                "articleId": 73,
                "lang": "en",
                "title": "New Progress in Lancang-Mekong Cooperation",
                "subtitle": "Countries Jointly Promote Regional Connectivity",
                "summary": "Recently, the LMC mechanism has made new progress...",
                "content": "

Detailed content...

", "author": "LMC Secretariat", "source": "Partner Platform A", "seoTitle": null, "seoKeywords": null, "seoDescription": null }, { "id": 154, "createTime": "2026-08-12 10:00:58", "updateTime": "2026-08-12 10:00:58", "articleId": 73, "lang": "zh-CN", "title": "澜湄合作新进展-更新了", "subtitle": "多国共同推进区域互联互通", "summary": "近日,澜湄合作机制迎来新进展...", "content": "

详细正文内容...

", "author": "联盟秘书处", "source": "合作伙伴平台A", "seoTitle": "澜湄合作新进展 - 官网", "seoKeywords": "澜湄,合作,区域互联", "seoDescription": "澜湄合作机制最新进展报告" } ], "tags": [ { "tagId": 1, "name": "New Tag 1" }, { "tagId": 2, "name": "标签2" } ] } } # 文章不存在 { "code": 2001, "message": "文章不存在" }
说明:

· lang 仅影响 tags[].name 的解析(请求语言 → en → 任意可用语言);若无匹配则 namenull
· i18n 始终返回文章已有的全部语言,不受 lang 限制,便于调用方按需取用。

更新文章

PUT /api/open/v1/cms/article/{id}

路径参数id — 平台生成的文章 ID(创建时返回的 article.id

请求体与创建接口字段一致,但均为可选。接口采用部分更新(patch 语义):仅覆盖请求体中传入的字段,未传入的字段与未传入的语言版本保持原值不变。响应结构与创建接口相同(article 为更新后主表记录,i18n 仅返回本次传入的语言列表)。

# 仅修改 zh-CN 的标题,其余字段与 en 版本均不变
PUT /api/open/v1/cms/article/123
{
  "i18n": [
    { "lang": "zh-CN", "title": "新标题" }
  ]
}

# 仅下架(status=0),其余全不变
PUT /api/open/v1/cms/article/123
{ "status": 0 }

# 清空标签:传空数组(不传 tagIds 字段则保留原标签)
PUT /api/open/v1/cms/article/123
{ "tagIds": [] }
部分更新规则:

· 主表字段:仅传入非 null 的字段被覆盖(viewCount 等未传字段永不被改动)。
· tagIds:仅当请求体包含该字段时才整体替换该文章标签;传 [] 表示清空,不传则保留原标签
· i18n:按 lang 增量更新——已存在的语言只更新请求中的非空字段、保留其余;未传入的语言完全不动;若 lang 不存在则插入新记录(此时 title 必填)。

撤稿(逻辑删除)

DELETE /api/open/v1/cms/article/{id}

路径参数id — 平台生成的文章 ID(创建时返回的 article.id)。

撤销已推送的文章。采用逻辑删除:主表 cms_articledeleted=1,数据保留、可恢复;同时级联物理清理 cms_article_i18ncms_article_tag 关联行,避免孤儿数据。门户侧按 deleted=0 过滤后将不再展示该文章。

DELETE /api/open/v1/cms/article/123

# 成功
{
  "code": 200,
  "message": "success",
  "data": null
}

# 文章不存在
{
  "code": 2002,
  "message": "Article not found",
  "data": null
}
注意:撤稿为逻辑删除,主表记录仍保留(deleted=1)。 若需重新发布,请调用 PUT /api/open/v1/cms/article/{id} 更新并恢复 status=1

关键返回字段说明

字段 用途
article.id 核心 — 外部平台必须保存,后续更新必需
article.status 确认是否已发布(1=发布,0=草稿)
i18n[].lang 确认各语言版本入库成功
i18n[].title 确认核心内容无误

外部平台接入指引

  1. 联系管理员创建 OpenApp,勾选 Scope cms:article:write
  2. 获取 AppIdAppSecret(仅展示一次)
  3. 实现 HMAC-SHA256 签名算法(见第 4 章)
  4. 调用 GET /api/open/v1/cms/category?lang=zh-CN 获取分类树,确定 categoryId
  5. 调用 GET /api/open/v1/cms/tag?lang=zh-CN 获取标签列表,确定 tagIds
  6. 构造请求体,计算签名,调用 POST /api/open/v1/cms/article
  7. 保存返回的 article.id,后续更新必需
  8. 如需更新,调用 PUT /api/open/v1/cms/article/{id}
  9. 如需撤稿,调用 DELETE /api/open/v1/cms/article/{id}
幂等性建议:外部平台可在本地维护 sourceId → articleId 映射。 同一篇文章重复推送时,建议先查本地映射,存在则调用 PUT 更新。

推送接口错误码

HTTP 状态码 Code 说明
400 2001 分类不存在
400 2003 标签不存在
404 2002 文章不存在(更新 / 撤稿时)
401 1604 签名无效
401 1605 时间戳过期
401 1606 Nonce 重复使用
403 1607 IP 不在白名单
429 1608 超出限流
403 1609 无对应 Scope 权限
400 1400 参数校验失败(如 lang 重复)

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

Scope 说明 状态
region:read 地区/国家 已开放
cms:category:read CMS 分类 已开放
cms:tag:read CMS 标签 已开放
cms:article:read CMS 文章读取 待扩展
cms:article:write 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