WackoWiki 6.3.0 API 使用详解

实测 WackoWiki 6.3.0 的 HTTP 接口:页面源码、修订历史与差异、XML 导出与 RSS 变更订阅、搜索、页面创建/编辑、附件上传下载、评论、逐页 ACL 与后台管理端点,含 Cookie 会话、一次性 nonce、409 覆盖告警与真实排障记录。

WackoWikiWackoWikiWiki知识库PHP2026/11/02

WackoWiki 6.3.0 API 使用详解

目标:WackoWiki 没有 REST/GraphQL JSON API,也没有命令行管理脚本或控制台;它对外真正可用的是 HTTP 页面接口、表单写入端点、RSS/XML 订阅与后台管理端点。本篇按 2026-11-02 的实测,把“怎么调、传什么、返回什么、哪里会失败”逐项讲清。软件定位与选型见《WackoWiki 介绍与选型指南》。

一、环境信息

  • WackoWiki 版本:6.3.0(官方发布日期 2026-07-18)
  • Web 服务:Apache 2.4.69(Debian),PHP 8.3.36
  • 数据库:MariaDB 11.4.13(11.4.13-MariaDB-ubu2404)
  • 站点名称:WackoWiki Demo
  • 站点根地址:http://localhost:8140/
  • 首页:HomePage
  • 测试页面:S9WackoDemo(页面/修订/搜索/订阅)、S9ApiDemo(创建/编辑/上传/评论/ACL)
  • 演示账号:root / q1w2e3r4;后台恢复口令同值(实验短口令,生产按 ≥15 位设置)
  • 客户端:curl 8.x(Ubuntu 26.04.1 LTS 宿主机)
  • 实测日期:2026-11-02

💡 接口定性:后台菜单只有 Web 表单,没有“管理脚本/控制台/CLI”。因此本篇按 API 使用篇(D5)编写,而不是 CLI 命令篇(D1)。机器可读输出集中在 _revisions.xml、_export.xml 与 xml/changes_*.xml 三类 XML;其余端点返回 HTML。

二、前置条件

  1. 站点可从服务器本机访问,首页返回 200:
BASE=http://localhost:8140
curl -sS -o /dev/null -w '%{http_code} %{content_type}\n' "$BASE/"
200 text/html; charset=utf-8
  1. 客户端具备 curl、grep、sed,并能保存 Cookie:
curl --version | head -1
curl 8.5.0 (x86_64-pc-linux-gnu) libcurl/8.5.0 OpenSSL/3.0.13 zlib/1.3
  1. 需要写入操作时准备管理员账号;只读接口可匿名访问(受页面 ACL 限制)。
  2. 写入端点全部依赖表单里的 _nonce,调用方必须先 GET 表单、取出 nonce,再 POST。
  3. 页面名区分大小写;URL 中的页面名就是 Wiki 页面标识(如 S9ApiDemo)。

三、接口总览

能力方法与路径认证/权限返回形态实测状态
首页/普通页面GET /、GET /<Page>按页面 read ACLHTML200
页面源码GET /<Page>/_sourceread ACLHTML(<pre>)200 / 403
修订历史GET /<Page>/_revisionsread ACLHTML200
修订订阅GET /<Page>/_revisions.xmlread ACLRSS 2.0200
版本差异GET /<Page>/_diff?a=&b=&diffmode=read ACLHTML200 / 403
单页导出GET /<Page>/_export.xmlexport_handler + 登录RSS 2.0200(可能含 Error item)
全站变更订阅GET /xml/changes_<站点名>.xml无RSS 2.0 静态文件200 / 404
搜索GET /Search?phrase=&topic=&p=无HTML200
新建/编辑页面GET /<Page>/_edit[?add=1] + POST /<Page>/_editwrite ACL + _nonce302 → HTML302
评论POST /<Page>/_addcommentcomment ACL + _nonce302 → HTML302
逐页 ACLPOST /<Page>/_permissionswrite ACL + _nonce302 → HTML302
上传附件GET/POST /<Page>/_uploadupload ACL + _nonce302 → HTML302
下载附件GET /<Page>/_file?get=<文件名>read ACL文件字节流200
附件元数据GET /<Page>/_filemeta?m=show&file_id=read ACLHTML200
后台管理GET/POST /admin.php?mode=Wiki 管理员会话 + 恢复口令HTML200 / 302

⚠️ 这不是 REST:没有资源路径版本号、没有 JSON、没有统一的错误体。写入用 application/x-www-form-urlencoded(上传用 multipart/form-data),成功统一返回 302 跳转,失败则返回 200/409 并在页面里给出提示文本。

四、认证与会话

4.1 前台登录

先 GET 登录页并保存 Cookie,同时从表单取出 _nonce:

curl -sS -c ck.txt -o login_get.html "$BASE/Login"
grep -o 'name="_nonce" value="[^"]*"' login_get.html | head -1
<input type="hidden" name="_nonce" value="B7U89uSXXLb" />

登录表单的关键字段:

字段示例值说明
_actionlogin固定动作
_nonceB7U89uSXXLb一次性 CSRF 令牌
user_nameroot用户名
passwordq1w2e3r4密码
persistent(可选)记住登录

提交:

curl -sS -b ck.txt -c ck.txt -L \
  --data-urlencode '_action=login' \
  --data-urlencode '_nonce=B7U89uSXXLb' \
  --data-urlencode 'user_name=root' \
  --data-urlencode 'password=q1w2e3r4' \
  -o login_post.html -D login_post.hdr \
  "$BASE/Login"

实测响应:

HTTP/1.1 302 Moved Temporarily
Server: Apache/2.4.69 (Debian)
X-Powered-By: PHP/8.3.36
Set-Cookie: LocalhostwSKwXXAuth=cHiIr_...; expires=Wed, 02 Dec 2026 10:34:42 GMT; Max-Age=2592000; path=/; httponly; SameSite=Lax
Location: /Users/Root?3xBZ
Content-Length: 0

跟随跳转后为 200,页面标题为:

<title>Root - WackoWiki Demo</title>

Cookie 名形如 LocalhostwSKwXXAuth,与站点主机名绑定;把 ck.txt 用作后续所有请求的会话即可。

错误口令返回 302 到 /Login?Redo,页面提示:

The username or password you have entered is invalid.

💡 curl 不加 -L 时只会看到 302 和空响应体,容易误判“登录失败”。判断登录成功应同时检查 Location 与 Cookie 罐。

4.2 一次性 nonce

所有写操作表单都带 _nonce。该令牌与表单绑定,用过一次即失效。重复提交同一个 nonce 时,页面返回:

The submitted form was invalid. Try submitting again.

调用约定:每个写请求前重新 GET 目标表单,解析 _nonce,再提交;不要缓存 nonce,也不要用 A 表单的 nonce 提交 B 表单。

4.3 后台二次认证

后台入口 /admin.php 有两道门:

  1. 当前会话必须是 Wiki 管理员;否则直接 302 到首页:
HTTP/1.1 302 Moved Temporarily
Location: /HomePage
  1. 通过第一道门后,页面要求输入后台恢复口令,标题为:
Administration Control Panel : Authorization

表单字段:

字段示例值说明
_actionap_login固定动作
_nonce表单值一次性令牌
ap_passwordq1w2e3r4恢复口令(config.php 中的 recovery_password)

登录成功后标题变为:

Administration Control Panel : Basic functions > Main Menu

⚠️ 恢复口令与前台用户密码是两套校验:前台密码在 wacko_user 表,恢复口令走 password_verify() 校验 recovery_password 哈希;两者不要混用。

五、读取接口

5.1 普通页面

curl -sS -D home.hdr -o home.html "$BASE/"

实测响应头:

HTTP/1.1 200 OK
Server: Apache/2.4.69 (Debian)
Content-Security-Policy: default-src 'self';base-uri 'self';form-action 'self';frame-ancestors 'self';...
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Content-Length: 4991
Content-Type: text/html; charset=utf-8

页面正文即 Wiki 渲染结果;没有“内容接口”,要拿结构化内容只能用下面的源码或导出端点。

5.2 页面源码 _source

curl -sS -o page_source "$BASE/S9WackoDemo/_source"

返回 HTML 中的 <pre> 就是原始 Wiki 标记:

<pre id="cb-CR636vQ" class="code source-handler">= WackoWiki 功能验证页 =
本页用于验证 WackoWiki 6.3.0 的页面创建、修订、搜索与附件功能。

== 列表 ==
* 创建页面
* 编辑并生成修订
* 全文检索

== 第二修订 ==
第二次编辑追加的段落,用于验证修订历史。

== 第三修订 ==
第三次编辑用于触发 RSS/XML 订阅文件生成。
</pre>

源码端点受页面 read ACL 控制。把页面 read 设为私有后,匿名访问返回 403:

HTTP/1.1 403 Forbidden
Content-Length: 3079
Content-Type: text/html; charset=utf-8

页面提示:

You aren't allowed to read this page.

5.3 不存在的页面

curl -sS -o notfound.html -w '%{http_code}\n' "$BASE/NoSuchPage12345"
404

页面标题与提示:

<title>No Such Page 12345 - WackoWiki Demo</title>
This page doesn't exist.

六、版本与导出接口

6.1 修订历史 _revisions

curl -sS -o page_revisions "$BASE/S9WackoDemo/_revisions"

页面列出该页全部修订,实测版本号为 3、2、1(倒序)。页面同时提供指向 _revisions.xml 的订阅链接。

6.2 修订订阅 _revisions.xml

curl -sS -o page_revisions.xml "$BASE/S9WackoDemo/_revisions.xml"

实测 200,1,503 字节,2 条 <item>;最新修订的链接为 ?revision_id=2,上一条为 ?revision_id=1:

<channel>
  <title>WackoWiki Demo - S9WackoDemo</title>
  <link>http://localhost:8140/S9WackoDemo</link>
  <description>Revisions of  WackoWiki Demo: S9WackoDemo</description>
  <language>en</language>
  <item>
    <title>Root: </title>
    <link>/S9WackoDemo?revision_id=2</link>
    <description><![CDATA[<br><strong>Additions:</strong><br>
      <div class="additions"><pre>== 第三修订 ==
第三次编辑用于触发 RSS/XML 订阅文件生成。
</pre></div>...]]></description>
    <pubDate>Mon, 02 Nov 2026 10:03:46 +0000</pubDate>
  </item>
  ...
</channel>

description 里是本次修订的增删片段,而不是整页正文。要拿整页正文应使用 _export.xml。

再次编辑 S9ApiDemo 后,该页的 _revisions.xml 为 1,835 字节,2 条 <item>,链接分别是 ?revision_id=4 与 ?revision_id=3。

6.3 版本差异 _diff

curl -sS -o diff.html "$BASE/S9WackoDemo/_diff?a=1&b=2"

实测 200,6,504 字节,标题 S9 Wacko Demo (diff) - WackoWiki Demo,差异片段:

<ins class="diff">== 第二修订 ==
第二次编辑追加的段落,用于验证修订历史。</ins>

diffmode 取值:

值模式说明
0Full diff完整差异(默认)
1Simple简化差异
2Source源码对照
3Side by side并排对照
4Inline行内差异
5Merged合并视图

a、b 必须是该页真实存在的修订 ID。实测在 S9ApiDemo 上传入不匹配的 a=1&b=2 会得到 403;用 a=3&b=4 则返回 200,标题 S9 API Demo (diff) - WackoWiki Demo。

6.4 单页导出 _export.xml

匿名请求:

curl -sS -o page_export.xml -w '%{http_code} %{size_download}\n' "$BASE/S9WackoDemo/_export.xml"
200 530

返回 200,但内容是错误条目:

<item>
  <title>Error</title>
  <link>/S9WackoDemo/show</link>
  <description>You're not allowed to access this information.</description>
</item>

带会话再请求:

curl -sS -b ck.txt -o export_auth.xml -w '%{http_code} %{size_download}\n' "$BASE/S9WackoDemo/_export.xml"
200 977

这次返回完整页面正文:

<item>
  <title>S9 Wacko Demo</title>
  <link>http://localhost:8140/S9WackoDemo</link>
  <description><![CDATA[= WackoWiki 功能验证页 =
本页用于验证 WackoWiki 6.3.0 的页面创建、修订、搜索与附件功能。

== 列表 ==
* 创建页面
* 编辑并生成修订
* 全文检索...
]]></description>
  <author>Root</author>
  <pubDate>Mon, 02 Nov 2026 10:02:41 GMT</pubDate>
</item>

原因在配置:export_handler=2 表示“仅登录用户可导出”。匿名不是收到 403,而是收到 200 + Error item——必须解析 item 标题,不能只看状态码。

七、订阅接口

站点级变更订阅的 URL 规则为:

/xml/changes_<站点名归一化>.xml

WackoWiki Demo 去掉非字母数字并转小写后得到 wackowikidemo:

curl -sS -o changes_now.xml -w '%{http_code} %{size_download}\n' \
  "$BASE/xml/changes_wackowikidemo.xml"
200 1238

实测内容(2 条记录,最新在前):

<channel>
  <title>WackoWiki Demo - Recent changes</title>
  <description>Recent changes to the WackoWiki Demo</description>
  <lastBuildDate>Mon, 02 Nov 2026 10:39:36 +0000</lastBuildDate>
  <item>
    <title>S9ApiDemo</title>
    <link>http://localhost:8140/S9ApiDemo/_diff?a=3&amp;b=&amp;diffmode=3</link>
    <guid>http://localhost:8140/S9ApiDemo</guid>
    <pubDate>Mon, 02 Nov 2026 10:39:36 +0000</pubDate>
    <description>2026-11-02 10:39:36 by Root</description>
  </item>
  <item>
    <title>S9WackoDemo</title>
    <link>http://localhost:8140/S9WackoDemo/_diff?a=2&amp;b=&amp;diffmode=3</link>
    <pubDate>Mon, 02 Nov 2026 10:05:37 +0000</pubDate>
    <description>2026-11-02 10:05:37 by Root</description>
  </item>
</channel>

要点:

  • 文件由页面保存/评论时生成,属于静态文件,不是每次请求实时查询;最新记录最多 30 条。
  • 文件写在站点根目录的 xml/ 下;该目录对 Web 进程不可写时,页面仍能保存,但订阅文件不会更新或直接 404。
  • 站点改名后 URL 随之变化,旧文件不会自动改名。
  • 本实例未启用评论订阅、新闻订阅与 Sitemap,实测 /xml/comments_wackowikidemo.xml、/xml/news_wackowikidemo.xml、/xml/sitemap_wackowikidemo.xml 均返回 404(324 字节的 404 页)。

八、搜索接口

curl -sS -o search.html "$BASE/Search?phrase=WackoWiki"

实测 200,5,570 字节,结果区文本:

Search results for «WackoWiki» (2):
Home Page        11/02/2026 09:10  -  System  - 331.0 B
Welcome to your WackoWiki ...
S9 Wacko Demo    11/02/2026 10:05  -  Root    - ...

标题搜索:

curl -sS -o search_topic.html "$BASE/Search?phrase=S9Api&topic=1"

实测 200,4,902 字节,命中 1 条:

results for «S9Api» (1): S9 API Demo  11/02/2026 10:41 - Root - 118.0 B

无结果时:

curl -sS -o search_nohit.html "$BASE/Search?phrase=zzz_no_such_term_2026"

页面文本:

No results for "zzz_no_such_term_2026"

参数:

参数取值默认说明
phrase任意字符串空少于 3 个字符不执行检索
topic1关闭只搜页面标题/标签,不搜正文
p页码1结果分页
max每页条数10覆盖系统默认值
lang语言代码空只搜指定 page_lang
scopepages / allallpages 只搜页面,all 含评论

分页示例:

curl -sS -o search_p2.html -w '%{http_code} %{size_download}\n' \
  "$BASE/Search?phrase=WackoWiki&p=2"
200 5570

本实例只有 2 条命中,p=2 仍返回同一结果集(页面没有第 2 页时回落到第 1 页内容)。结果按相关度(MySQL MATCH ... AGAINST 分数)倒序,标题搜索按页面标签排序。

九、写入接口:页面创建与编辑

9.1 取编辑表单

新页面用 ?add=1:

curl -sS -b ck.txt -o edit_new.html -w '%{http_code} %{size_download}\n' \
  "$BASE/S9ApiDemo/_edit?add=1"
200 8003

表单字段:

字段示例值说明
_actionedit_page固定动作
_nonce7gv33IpDuYP一次性令牌
section0整页编辑;其他值表示段落编辑
h_level1标题层级
previous2026-11-02&#x20;10&#x3A;35&#x3A;25编辑基线时间(HTML 实体编码)
titleS9 API Demo页面标题
body多行文本Wiki 正文

9.2 创建页面

curl -sS -b ck.txt -c ck.txt -o create_page.html -D create_post.hdr \
  --data-urlencode '_action=edit_page' \
  --data-urlencode '_nonce=7gv33IpDuYP' \
  --data-urlencode 'section=0' \
  --data-urlencode 'h_level=1' \
  --data-urlencode 'previous=2026-11-02&#x20;10&#x3A;35&#x3A;25' \
  --data-urlencode 'title=S9 API Demo' \
  --data-urlencode 'body=//S9 API demo page//

Created via HTTP form API at 2026-11-02.' \
  "$BASE/S9ApiDemo/_edit"

实测响应:

HTTP/1.1 302 Moved Temporarily
Location: /S9ApiDemo
Content-Length: 0

跟随跳转后 200,页面创建成功,page_id=18,version_id=3,revisions=2(创建算 1 次修订,随后编辑再生成 1 次)。

9.3 二次编辑与覆盖保护

再次编辑必须先 GET 当前页面编辑表单,原样取回 previous:

curl -sS -b ck.txt -o edit4.html "$BASE/S9ApiDemo/_edit"

实测 previous 为:

2026-11-02&#x20;10&#x3A;39&#x3A;36

即 HTML 实体编码的空格(&#x20;)与冒号(&#x3A;)。提交前必须解码为 2026-11-02 10:39:36,否则服务端判定基线不一致,返回 409 与提示:

HTTP/1.1 409 Conflict
OVERWRITE ALERT: This page was modified by someone else while you were editing it.
Please copy your changes and re-edit this page.

解码后提交:

curl -sS -b ck.txt -c ck.txt -o edit4_after.html -D edit4_post.hdr \
  --data-urlencode '_action=edit_page' \
  --data-urlencode '_nonce=<取自 edit4.html>' \
  --data-urlencode 'section=0' \
  --data-urlencode 'h_level=1' \
  --data-urlencode 'previous=2026-11-02 10:39:36' \
  --data-urlencode 'title=S9 API Demo' \
  --data-urlencode 'body=//S9 API demo page//

Created via HTTP form API at 2026-11-02.

== 第二版 ==
Revision created through the edit API.' \
  "$BASE/S9ApiDemo/_edit"

实测 302 → /S9ApiDemo,随后 200,version_id=3、revisions=2 保持不变(同一修订链按版本号推进)。

⚠️ previous 的 HTML 实体是踩坑高发点:直接从页面复制 hidden 值会带入 &#x20; 与 &#x3A;,看起来是空格和冒号,服务端按字面比较就会冲突。用脚本解析时必须解码。

十、评论与逐页 ACL

10.1 发表评论

评论表单在页面底部,动作路径为 /<Page>/_addcomment,字段:

字段示例值说明
_actionadd_comment固定动作
_nonce表单值一次性令牌
parent_id0顶层评论
title(可选)评论标题
body多行文本评论正文

提交实测返回:

HTTP/1.1 302 Moved Temporarily
Location: /S9ApiDemo?show_comments=1&p=last#Comment1
Content-Length: 0

跟随跳转后页面出现:

Comment added.

10.2 逐页 ACL

表单路径为 /<Page>/_permissions,动作 _action=set_permissions,五个 textarea 分别对应五类权限:

字段权限实测值
read_acl读*
write_acl写Admins\nModerator
comment_acl评论Admins
create_acl创建子页$
upload_acl上传Admins

规则:

  • 一行一个主体,不是逗号分隔。写成 Admins,Moderator 会得到 Access control list syntax error。
  • * 表示所有人(含匿名),$ 表示已注册用户,其余按用户名/组名匹配。
  • 提交成功后页面提示:
Access control lists updated
  • 再次提交同一个 _nonce 会得到 The submitted form was invalid. Try submitting again.,必须重新 GET 表单。

十一、附件上传与下载

11.1 上传

上传表单路径 /<Page>/_upload,enctype="multipart/form-data",字段:

字段示例值说明
_actionupload固定动作
_noncevPRHqIPWGUD一次性令牌
upload1必须为 1,缺失会被当作普通页面请求
MAX_FILE_SIZE512000表单侧上限(字节)
upload_tolocal / global页面级附件或全局附件
file文件待上传文件
file_description(可选)附件说明
file_overwrite1允许覆盖同名文件

提交:

curl -sS -b ck.txt -c ck.txt -o upload_after2.html -D upload_post2.hdr \
  -F '_action=upload' \
  -F '_nonce=vPRHqIPWGUD' \
  -F 'upload=1' \
  -F 'MAX_FILE_SIZE=512000' \
  -F 'upload_to=local' \
  -F 'file=@s9api-upload.txt;type=text/plain' \
  -F 'file_description=API upload test' \
  "$BASE/S9ApiDemo/_upload"

实测响应:

HTTP/1.1 302 Moved Temporarily
Location: /S9ApiDemo/_filemeta?m=show&file_id=3
Content-Length: 0

跟随跳转后页面提示:

File upload successful

11.2 下载

curl -sS -D file_dl.hdr -o file_dl.bin \
  "$BASE/S9ApiDemo/_file?get=s9api-upload.txt"

实测响应头:

HTTP/1.1 200 OK
Server: Apache/2.4.69 (Debian)
Cache-Control: max-age=2592000
Last-Modified: Mon, 02 Nov 2026 10:35:45 GMT
Content-Length: 37
Content-Disposition: inline; filename="s9api-upload.txt"
X-Content-Type-Options: nosniff
Content-Type: text/plain;charset=UTF-8

正文 37 字节,即上传文本原样返回。下载走页面的 read ACL,不额外校验上传者身份。

11.3 附件元数据

curl -sS -b ck.txt -o files.html "$BASE/S9ApiDemo/_filemeta?m=show&file_id=3"

返回附件详情页(文件名、大小、上传者、下载链接等),适合在脚本里核对上传结果。

十二、后台管理接口

后台只有 Web 入口 /admin.php?mode=<模块>,没有 JSON API。常用模块:

mode页面用途
system_infoSystem Info版本、PHP/Apache/数据库、扩展、目录权限
system_statisticsStatistics各表记录数、目录文件数与体积
system_logSystem Log系统日志(最多 100 条)
db_backupDatabase Backup按表/目录导出备份
db_restoreDatabase Restore恢复备份
db_repairDatabase Repair表检查/修复
user_usersUsers用户列表、编辑、删除
user_groupsGroups用户组管理
config_basic 等Configuration基础/外观/邮件/权限/安全/上传等分组设置
content_menu / content_deletedContent菜单与已删除页面
maint_resync / maint_inconsistenciesMaintenance重同步与一致性检查

12.1 系统信息

curl -sS -b ck.txt -o admin_system_info.html "$BASE/admin.php?mode=system_info"

实测页面关键值:

WackoWiki 6.3.0
Apache/2.4.69 (Debian)
MariaDB 11.4.13
PHP 8.3.36
UTF-8
memory_limit 128.0 MiB

12.2 系统日志与过滤

curl -sS -b ck.txt -o admin_system_log.html "$BASE/admin.php?mode=system_log"
grep -o 'name="_action" value="[^"]*"' admin_system_log.html
name="_action" value="systemlog"

日志表单字段 level_mod(阈值关系)与 level(级别):

字段实测可选值说明
level_modequal / not higher than等于 / 不高于
level1: critical、2: highest、3: high、4: medium、5: low、6: lowest日志级别
p页码分页,单页最多 100 条

提交筛选(level_mod=2、level=3)后,页面回显:

<option value="2" selected>not higher than</option>
<option value="3" selected>3: high</option>

12.3 用户列表与排序

curl -sS -b ck.txt -o admin_users_sorted.html \
  "$BASE/admin.php?mode=user_users&order=user_name_desc&user=Root"

实测命中管理员行:

Root  root@example.com  2  1  3  3  en

参数:

参数说明
order排序,如 user_name_desc
user按用户名过滤
p页码

12.4 数据库备份

curl -sS -b ck.txt -o admin_db_backup.html "$BASE/admin.php?mode=db_backup"

页面表单按表提供 __str__<table>(结构)与 __dat__<table>(数据)复选框,另有 __dir__file/global、__dir__file/perpage 目录备份项与 log_note 备注。实测覆盖 wacko_acl、wacko_page、wacko_revision、wacko_user、wacko_config 等表。

⚠️ 后台所有写操作同样带 _nonce,且后台会话与前台会话共用 Cookie;先用前台管理员登录,再完成 ap_login,顺序反了会 302 回首页。

十三、分页、过滤与排序汇总

端点分页参数过滤/排序单页上限
/Searchpphrase、topic、lang、scopemax,默认 10
/<Page>/_revisions—limit(默认 100)、minor、deleted100
/<Page>/_revisions.xml—最新在前由 _revisions 的 limit 控制
/xml/changes_<site>.xml—最新在前30
/admin.php?mode=system_logplevel、level_mod、order100
/admin.php?mode=user_userspuser、order按后台设置

通用约定:页码从 1 开始;页码越界时回落到第 1 页;过滤条件变化后页码应重置。

十四、错误码与排障实录

14.1 状态码

状态场景响应特征
200正常读取、搜索、后台页面HTML;导出/订阅为 XML
200 + Error item匿名 _export.xml<title>Error</title>,正文为权限提示
302登录成功、写入成功、未授权进后台Location 指向目标页或 /HomePage
403私有页面 _source;diff 修订 ID 不匹配3,079 字节 HTML,You aren't allowed to read this page.
404页面不存在;未生成的订阅文件3,068 字节 HTML,This page doesn't exist.;XML 路径为 324 字节 404 页
409编辑基线不一致OVERWRITE ALERT

14.2 排障实录

问题 1:写操作返回 The submitted form was invalid. Try submitting again.

原因:复用了已消费的 _nonce,或 nonce 与表单动作不匹配。 处理:每次写请求前重新 GET 目标表单,解析并立即使用新的 _nonce。

问题 2:二次编辑 409 OVERWRITE ALERT

原因:previous 直接照抄页面 hidden 值,带着 &#x20; 与 &#x3A; 实体;服务端按字面比较,判定页面已被他人修改。 处理:提交前把实体解码为空格与冒号;或从编辑页 hidden 值原样回传但由客户端做 HTML 解码。

问题 3:上传不成功,页面回到普通视图

原因:漏传 upload=1 或 upload_to。缺少 upload=1 时服务端不会进入上传分支。 处理:按第 11 节的字段表补齐,upload_to 显式取 local 或 global。

问题 4:_export.xml 返回 200 但只有 Error item

原因:export_handler=2 要求登录;匿名请求不会得到 403,而是 200 + Error。 处理:带管理员/读者会话请求,或在后台把 export_handler 调成允许匿名导出。

问题 5:/xml/changes_*.xml 404

原因:xml/ 目录对 Web 进程不可写,页面保存时无法生成静态订阅文件。 处理:修正 xml/ 属主/权限,保存任意页面触发重建;确认文件名中的站点名已归一化。

问题 6:/admin.php 直接 302 到 /HomePage

原因:当前会话不是 Wiki 管理员,第一道门未通过,还没到恢复口令页。 处理:先完成前台管理员登录,再访问后台并提交 ap_password。

问题 7:_diff 返回 403

原因:a/b 不是该页真实修订 ID,或当前用户无该页读权限。 处理:先从 _revisions 或 _revisions.xml 取得修订 ID,再拼接 _diff。

问题 8:curl 登录返回空响应

原因:未加 -L,只看到 302 的空响应体。 处理:加 -L 跟随跳转,同时用 -c 保存 Cookie 罐。

问题 9:搜索无结果

原因:关键词少于 3 个字符时服务端不执行检索;或内容不在正文/标题中。 处理:使用 ≥3 字符的关键词;标题搜索加 topic=1;必要时放宽 scope=all。

十五、参考链接

WackoWiki 6.3.0 API 使用详解 - Quzuo