API 使用教程

从零开始接入 留言板API。本教程将带你完成密钥获取、接口认证、留言提交、列表查询等全部操作,并提供 cURL、JavaScript、Python、PHP 示例代码。

RESTful JSON 7 个端点 GET / POST
1

获取密钥

在后台创建 API Key,配置域名白名单

2

理解认证

掌握 URL 参数与 JSON Body 两种传参方式

3

调用接口

提交留言、获取列表、回复互动

4

接入上线

处理错误、优化性能、保障安全

🚀 准备工作

在调用 API 之前,你需要完成以下三步准备工作。这些步骤确保你的请求能够被正确识别和授权。

  1. 访问后台管理 打开 后台管理 页面,使用管理员账号登录。如果你是第一次使用,请先运行 install.php 完成系统安装。
  2. 创建 API Key 进入「API 管理」→「新增 API Key」,填写一个便于识别的名称(如"我的博客")。系统会生成一串唯一的密钥,请妥善保存。
  3. 配置域名白名单 在 API Key 详情中设置允许调用的域名。支持精确匹配 example.com 和通配符 *.example.com。留空表示不限制,但强烈建议填写,防止密钥泄露后被滥用。
🔒 安全提示:API Key 相当于访问凭证,请勿直接写在前端公开代码中。生产环境建议由服务端代理请求,前端只与你的后端通信。

🔑 认证与 Base URL

所有接口(除全局统计外)都需要认证。API 使用统一的入口地址,并通过 api_key 参数识别调用者身份。

API Base URL
https://ly.wzu.me/api.php
数据格式
JSON(UTF-8 编码)
认证参数
api_key
请求方法
GET / POST

两种传参方式

API 支持两种方式传递 api_key 和其他参数,你可以根据场景选择最合适的方式。

方式一:URL 参数(推荐用于 GET 请求)

将参数附加在 URL 末尾,适合浏览器直接访问和简单的 GET 查询。

URL
GET https://ly.wzu.me/api.php?action=verify&api_key=YOUR_KEY

方式二:JSON Body(推荐用于 POST 请求)

将参数放在请求体中,需设置请求头 Content-Type: application/json。适合提交留言、回复等写操作。

JSON
{
  "api_key": "YOUR_KEY",
  "nickname": "小明",
  "content": "留言内容"
}
💡 优先级说明:如果 URL 参数和 JSON Body 同时提供了同一个字段,系统会以 JSON Body 中的值为准。但建议每个参数只使用一种方式传递,避免混淆。

通用响应格式

无论调用哪个接口,成功或失败都会返回统一的 JSON 结构:

{ "code": 200, "msg": "成功", "data": {} }
code业务状态码,200 表示成功,其他值为失败
msg可读提示信息,用于错误排查和展示
data业务数据,不同接口返回不同结构;失败时可能为空

发送第一个请求

下面使用验证接口测试你的 API Key 是否有效。这是最简单的接口,只需一个 api_key 参数。

GET /api.php?action=verify 验证密钥

测试 API Key 是否有效,同时返回该密钥的备注名称。建议接入前先调用此接口确认密钥配置正确。

请求参数

参数类型必填说明
api_keystring必填在后台生成的 API Key

调用示例

bash
curl "https://ly.wzu.me/api.php?action=verify&api_key=YOUR_KEY"
javascript
fetch('https://ly.wzu.me/api.php?action=verify&api_key=YOUR_KEY')
  .then(res => res.json())
  .then(data => console.log(data));
python
import requests

url = 'https://ly.wzu.me/api.php?action=verify&api_key=YOUR_KEY'
res = requests.get(url)
print(res.json())
php
$res = file_get_contents('https://ly.wzu.me/api.php?action=verify&api_key=YOUR_KEY');
$data = json_decode($res, true);
print_r($data);

成功响应

{ "code": 200, "msg": "API Key 有效", "data": { "name": "我的博客" } }

常见错误响应

{ "code": 401, "msg": "缺少 api_key 参数" }
{ "code": 403, "msg": "无效的 api_key" }

📝 提交留言

提交一条新留言。系统会自动识别 IP 归属地、设备信息,并进行敏感词过滤、垃圾检测和 IP 限流。

POST /api.php?action=post 提交留言

向指定 API Key 对应的留言空间提交一条留言。留言提交后需要管理员在后台审核通过,才会显示在列表中。

请求参数

参数类型必填限制说明
api_keystring必填-API 密钥
nicknamestring必填≤ 30 字符留言者昵称
contentstring必填≤ 500 字符留言内容
emailstring可选合法邮箱填写后若有人回复,系统会自动发送邮件通知
💡 安全过滤:内容会经过敏感词检测和垃圾信息检测。如果命中敏感词,返回 400;如果被识别为垃圾信息,同样返回 400。建议前端提示用户修改后重试。

调用示例

bash
curl -X POST "https://ly.wzu.me/api.php?action=post" \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "YOUR_KEY",
    "nickname": "小明",
    "content": "这个功能非常好用!",
    "email": "xiaoming@example.com"
  }'
javascript
fetch('https://ly.wzu.me/api.php?action=post', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    api_key: 'YOUR_KEY',
    nickname: '小明',
    content: '这个功能非常好用!',
    email: 'xiaoming@example.com'
  })
})
.then(res => res.json())
.then(data => {
  if (data.code === 200) {
    console.log('留言成功,ID:', data.data.id);
  } else {
    console.error('提交失败:', data.msg);
  }
});
python
import requests

url = 'https://ly.wzu.me/api.php?action=post'
payload = {
    'api_key': 'YOUR_KEY',
    'nickname': '小明',
    'content': '这个功能非常好用!',
    'email': 'xiaoming@example.com'
}
res = requests.post(url, json=payload)
print(res.json())
php
$ch = curl_init('https://ly.wzu.me/api.php?action=post');
$payload = json_encode([
    'api_key' => 'YOUR_KEY',
    'nickname' => '小明',
    'content' => '这个功能非常好用!',
    'email' => 'xiaoming@example.com'
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$res = curl_exec($ch);
print_r(json_decode($res, true));

成功响应

{ "code": 200, "msg": "留言成功", "data": { "id": 42 } }

常见错误响应

{ "code": 400, "msg": "昵称和留言内容不能为空" }
{ "code": 429, "msg": "留言过于频繁,请30秒后再试" }

💬 回复留言

以访客身份回复某条留言,支持多轮互动。回复内容同样会经过敏感词过滤。

POST /api.php?action=reply 访客回复

回复一条已存在且审核通过的留言。如果留言者填写了邮箱,系统会自动发送邮件通知。回复不会立即出现在列表中,需要管理员审核后随主留言一起展示。

请求参数

参数类型必填限制说明
api_keystring必填-API 密钥
message_idint必填-被回复的留言 ID
nicknamestring必填≤ 30 字符回复者昵称
contentstring必填≤ 500 字符回复内容
emailstring可选合法邮箱回复者邮箱

调用示例

bash
curl -X POST "https://ly.wzu.me/api.php?action=reply" \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "YOUR_KEY",
    "message_id": 42,
    "nickname": "小红",
    "content": "我也觉得很好用!"
  }'
javascript
fetch('https://ly.wzu.me/api.php?action=reply', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    api_key: 'YOUR_KEY',
    message_id: 42,
    nickname: '小红',
    content: '我也觉得很好用!'
  })
})
.then(res => res.json())
.then(data => console.log(data));
python
import requests

url = 'https://ly.wzu.me/api.php?action=reply'
payload = {
    'api_key': 'YOUR_KEY',
    'message_id': 42,
    'nickname': '小红',
    'content': '我也觉得很好用!'
}
res = requests.post(url, json=payload)
print(res.json())
php
$ch = curl_init('https://ly.wzu.me/api.php?action=reply');
$payload = json_encode([
    'api_key' => 'YOUR_KEY',
    'message_id' => 42,
    'nickname' => '小红',
    'content' => '我也觉得很好用!'
]);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
print_r(json_decode(curl_exec($ch), true));

成功响应

{ "code": 200, "msg": "回复成功", "data": { "id": 15 } }

常见错误响应

{ "code": 404, "msg": "留言不存在或已隐藏" }

📋 留言列表

分页获取已审核通过的留言,包含 IP 归属地、设备信息、管理员回复以及最新访客回复。

GET /api.php?action=list 留言列表

获取当前 API Key 对应的留言空间中的已审核留言列表。支持分页,每页最多 50 条。返回结果包含管理员最新回复和最近访客回复列表。

请求参数

参数类型必填默认值说明
api_keystring必填-API 密钥
pageint可选1页码,从 1 开始
per_pageint可选10每页数量,最大 50

调用示例

bash
curl "https://ly.wzu.me/api.php?action=list&api_key=YOUR_KEY&page=1&per_page=10"
javascript
const params = new URLSearchParams({
  action: 'list',
  api_key: 'YOUR_KEY',
  page: '1',
  per_page: '10'
});
fetch(`https://ly.wzu.me/api.php?${params}`)
  .then(res => res.json())
  .then(data => {
    if (data.code === 200) {
      data.data.messages.forEach(msg => console.log(msg));
    }
  });
python
import requests

params = {
    'action': 'list',
    'api_key': 'YOUR_KEY',
    'page': 1,
    'per_page': 10
}
res = requests.get('https://ly.wzu.me/api.php', params=params)
print(res.json())
php
$url = 'https://ly.wzu.me/api.php?action=list&api_key=YOUR_KEY&page=1&per_page=10';
$res = file_get_contents($url);
print_r(json_decode($res, true));

成功响应

{ "code": 200, "msg": "成功", "data": { "total": 128, "page": 1, "per_page": 10, "total_pages": 13, "messages": [ { "id": 42, "nickname": "小明", "content": "这个功能非常好用!", "city": "中国 广东 深圳", "device_info": "电脑 | Windows 10/11 | Chrome 120", "created_at": "2026-07-11 14:30:00", "replies": [ { "id": 1, "nickname": "管理员", "content": "感谢支持!", "is_admin": 1, "created_at": "2026-07-11 15:00:00" } ] } ] } }

返回字段说明

total该 API Key 下的留言总数
page当前请求的页码
per_page每页返回数量
total_pages总页数
messages留言对象数组
messages[].id留言唯一 ID
messages[].nickname留言者昵称
messages[].content留言内容
messages[].city根据 IP 解析的归属地
messages[].device_info设备、操作系统、浏览器信息
messages[].created_at留言创建时间
messages[].replies回复列表,无回复时为空数组
replies[].nickname回复者昵称
replies[].content回复内容
replies[].is_admin是否管理员回复(1=是,0=否)

🔍 留言详情

根据留言 ID 获取单条留言的完整信息,包含所有回复(管理员回复和用户回复)。

GET /api.php?action=detail 留言详情

当你需要展示单条留言详情页,或者从列表点击某条留言查看完整内容时,可以使用此接口。

请求参数

参数类型必填说明
api_keystring必填API 密钥
idint必填留言 ID

调用示例

bash
curl "https://ly.wzu.me/api.php?action=detail&api_key=YOUR_KEY&id=42"
javascript
fetch('https://ly.wzu.me/api.php?action=detail&api_key=YOUR_KEY&id=42')
  .then(res => res.json())
  .then(data => console.log(data));

成功响应

{ "code": 200, "msg": "成功", "data": { "id": 42, "nickname": "小明", "content": "这个功能非常好用!", "city": "中国 广东 深圳", "device_info": "电脑 | Windows 10/11 | Chrome 120", "created_at": "2026-07-11 14:30:00", "replies": [ { "id": 1, "nickname": "管理员", "content": "感谢支持!", "is_admin": 1, "created_at": "2026-07-11 15:00:00" }, { "id": 2, "nickname": "小红", "content": "我也觉得很好用!", "is_admin": 0, "created_at": "2026-07-11 16:00:00" } ] } }

📊 留言统计

获取当前 API Key 下的留言总数和今日新增数量。

GET /api.php?action=count 留言统计

适用于在网站侧边栏展示"已有 XX 条留言"、"今日 XX 条留言"等统计信息。

请求参数

参数类型必填说明
api_keystring必填API 密钥

调用示例

bash
curl "https://ly.wzu.me/api.php?action=count&api_key=YOUR_KEY"

成功响应

{ "code": 200, "msg": "成功", "data": { "total": 128, "today": 5 } }

📈 全局统计

获取所有 API Key 的总调用次数、留言总数和活跃站点数。此接口无需认证,可公开调用。

GET /api.php?action=stats 全局统计

通常用于首页展示平台级数据,如总 API 调用次数、总留言数、活跃站点数。

💡 无需认证:此接口不需要 api_key,可直接通过浏览器或前端调用。首页的实时统计数字就是通过此接口获取的。

调用示例

bash
curl "https://ly.wzu.me/api.php?action=stats"

成功响应

{ "code": 200, "msg": "成功", "data": { "total_api_calls": 12580, "total_messages": 4320, "total_sites": 15 } }

🛠️ 完整接入流程

下面展示如何从零开始,在你的网页中嵌入一个完整的留言板功能。

1

创建 HTML 结构

准备一个表单用于提交留言,一个列表区域用于展示留言。

html
<form id="msgForm">
  <input type="text" id="nickname" placeholder="昵称" required>
  <textarea id="content" placeholder="留言内容" required></textarea>
  <button type="submit">提交留言</button>
</form>
<div id="msgList">加载中...</div>
2

加载留言列表

页面加载时调用 action=list 接口,将返回的留言渲染到页面中。

javascript
const API_KEY = 'YOUR_KEY';
const API_BASE = 'https://ly.wzu.me/api.php';

async function loadMessages(page = 1) {
  const res = await fetch(`${API_BASE}?action=list&api_key=${API_KEY}&page=${page}&per_page=10`);
  const json = await res.json();
  if (json.code !== 200) return alert('加载失败:' + json.msg);

  const list = document.getElementById('msgList');
  list.innerHTML = json.data.messages.map(m => `
    <div class="msg-item">
      <strong>${m.nickname}</strong> <span>${m.city}</span>
      <p>${m.content}</p>
      <small>${m.created_at}</small>
      ${(m.replies || []).map(r =>
        r.is_admin
          ? `<p style="color:#6366f1">管理员回复:${r.content}</p>`
          : `<p style="color:#06b6d4">${r.nickname} 回复:${r.content}</p>`
      ).join('')}
    </div>
  `).join('');
}

loadMessages();
3

提交新留言

监听表单提交事件,调用 action=post 接口,提交成功后重新加载列表。

javascript
document.getElementById('msgForm').addEventListener('submit', async (e) => {
  e.preventDefault();
  const res = await fetch(`${API_BASE}?action=post`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      api_key: API_KEY,
      nickname: document.getElementById('nickname').value,
      content: document.getElementById('content').value
    })
  });
  const json = await res.json();
  if (json.code === 200) {
    alert('留言提交成功,等待审核');
    loadMessages();
  } else {
    alert('提交失败:' + json.msg);
  }
});

⚠️ 错误处理

了解每个错误码的含义,并编写对应的处理逻辑,可以让你的应用更健壮。

状态码含义建议处理
200请求成功正常处理返回数据
400参数错误、内容超长、包含敏感词或垃圾信息提示用户检查输入内容,修改后重试
401缺少 api_key 参数检查请求是否携带了 api_key
403api_key 无效、已禁用或当前域名不在白名单检查密钥是否正确,域名白名单是否配置
404留言不存在或 action 参数未知检查 ID 是否正确,action 是否拼写正确
405请求方法不允许确认 POST 接口使用 POST,GET 接口使用 GET
429请求过于频繁,触发 IP 限流等待一段时间后重试,建议增加前端提交间隔
javascript
async function apiCall(url, options = {}) {
  const res = await fetch(url, options);
  const json = await res.json();
  if (json.code === 200) return json.data;

  switch (json.code) {
    case 400: throw new Error('内容格式错误:' + json.msg);
    case 401: throw new Error('缺少 API Key');
    case 403: throw new Error('权限不足:' + json.msg);
    case 429: throw new Error('操作过于频繁,请稍后再试');
    default:  throw new Error(json.msg);
  }
}

🌟 最佳实践

遵循以下建议,确保 API 调用的安全性、稳定性和用户体验。

🔒 不要在客户端暴露 API Key。生产环境建议由服务端代理请求,前端只与你的后端通信。如果必须在前端调用,务必配置严格的域名白名单。
🌐 配置域名白名单。支持通配符 *.example.com。即使密钥被泄露,没有正确的域名也无法调用。
⏱️ 合理使用缓存。留言列表等读接口可以适当缓存(建议 30-60 秒),减少 API 调用次数。提交接口不要缓存。
🔄 错误重试。遇到 429(限流)时不要立即重试,建议等待 30 秒以上。可使用指数退避策略。
📝 前端校验。提交前检查昵称和内容长度,避免提交到服务端后才发现超长。但服务端校验仍然是最终保障。

常见问题

接入过程中经常遇到的问题及解答。

新提交的留言默认需要管理员在后台审核通过后才能展示。请登录后台,进入「留言管理」,将留言状态设为「已通过」。
浏览器调用会携带 Origin/Referer 头,如果域名白名单不匹配就会返回 403。请检查后台配置的域名白名单是否包含你前端页面的实际域名(注意是否包含 www 或端口号)。
API 已经设置了 Access-Control-Allow-Origin: *,支持跨域。但跨域请求仍会受域名白名单限制,请确保白名单已配置。
不支持。留言内容会按纯文本存储和展示,提交 HTML 标签会被转义,防止 XSS 攻击。如需富文本,建议在前端自行渲染 Markdown 到 HTML 后提交,但需注意安全风险。
默认每个 IP 在 30 秒内只能提交一次留言。管理员可以在后台「垃圾拦截设置」中调整 ip_rate_limit_seconds 的值。