MistServer 3.12 Management API 使用详解

基于 ddvtech/mistserver:3.12 实测:JSON 请求模型与三种提交方式差异、challenge-response 认证算法与四态状态机、命令矩阵、流生命周期 API 实操与三类排障实录。

MistServerMistServer流媒体2026/10/30

MistServer 3.12 Management API 使用详解

目标:把 MistServer 3.12 的 Management API 从认证到命令族一次讲透并全部实测:JSON 请求模型与三种提交方式的实测差异、challenge-response 认证算法与四态状态机、以配置域为轴的命令矩阵、流生命周期(建流-推流-查询-销毁)的完整 API 实操,以及"请求返回 OK 但配置没变"等三类实测排障。全部结论来自 2026-10-30 对 ddvtech/mistserver:3.12 的实查。

本文是 MistServer 系列的第四篇。MistServer 的运维哲学是"API 即全量状态":Web 管理界面本身就是这套 API 的一个单页实现(实测:浏览器直接访问 4242 端口根路径返回的 762KB 单页应用,所有界面操作都是 API 调用)。所以读懂 API 就等于读懂 MistServer 的全部运维能力。配置字段的含义见 《MistServer 3.12 配置参数详解》,部署与选型见系列前两篇。

一、API 总览:请求模型与端口

1.1 基本约定

项目实测值
端口4242(管理口,Web 界面与 API 同口;可由启动参数/配置修改)
端点任意路径均可(无效路径返回 Web 界面单页);/api 与 /api2 保证返回 JSON
请求载荷HTTP 参数名 command,值是 JSON 对象字符串;或 Content-Type: application/json 的 JSON 请求体
响应JSON 对象;authorize 成员总是返回
JSONP请求带 callback 或 jsonp 参数时按 JSONP 包装返回

/api 与 /api2 的实测差异(官方文档明示 + 实测验证):streams、config、log 三类响应总是随 /api 返回(即使未请求);/api2 自动带 minimal 语义,只返回请求的成员。程序化对接建议用 /api2 精确取数,调试时用 /api 一把梭看全量。

1.2 三种提交方式的实测结论

实测用同一写命令(addstream)分别走三种提交方式,结论:

方式认证写操作实测结果
GET ?command=<URL 编码 JSON>✅✅完全可用
POST + Content-Type: application/json(JSON 体)✅✅完全可用(推荐)
POST + application/x-www-form-urlencoded(command=<JSON>)✅❌认证通过但写成员不生效(详见第九节实录一)

关键实测证据(form 表单方式):请求体 command={"addstream":{"testapi":...},"authorize":{...}} 提交后返回 {"authorize":{"status":"OK"}},但随后读回 streams 无 testapi;改用 JSON 体提交同一命令,testapi 立即出现。结论:程序化对接一律用 JSON 请求体。

二、认证:challenge-response 全流程

2.1 四态状态机

authorize 响应状态实测全集:

status含义实测触发条件
NOACC服务无任何账号全新首启(配置里 account 为空)
ACC_MADE初始账号已创建NOACC 状态下提交 new_username/new_password 成功
CHALL待认证(附 challenge 串)有账号但当前请求未携带有效认证
OK已认证认证对象校验通过

非 OK 状态下,服务端只响应认证类请求,其余命令一律不执行——实测中 command=get 在 CHALL 状态下只返回 authorize 成员。

2.2 密码摘要算法(实测验证)

算法(官方文档明示,实测复算一致):

存储摘要 = MD5(明文密码)
登录串   = MD5(存储摘要 + challenge)

实测验证:明文 q1w2e3r4 的 MD5 为 c62d929e7b7e7b6165923a5dfc60cb56,与持久化文件 account.root.password 一致;以 challenge 750094e2... 计算登录串后认证返回 OK。

2.3 完整登录实测(Python 参考客户端)

以下脚本从拿 challenge 到带认证读全量状态一次跑通(实测输出见注释):

import urllib.request, hashlib, json

BASE = 'http://<服务器IP>:4242/api'
PWD  = 'q1w2e3r4'          # 演示账号;生产环境用强密码
md5  = lambda s: hashlib.md5(s.encode()).hexdigest()

# 第 1 步:拿 challenge(空对象请求)
r = json.load(urllib.request.urlopen(BASE + '?command=%7B%7D'))
challenge = r['authorize']['challenge']          # 形如 '750094e22eeba5133eb3acec419bb6eb'
# 第 2 步:计算登录串并随业务命令提交
cmd = {'streams': None,
       'authorize': {'username': 'root',
                     'password': md5(md5(PWD) + challenge)}}
body = json.dumps(cmd).encode()
req  = urllib.request.Request(BASE, data=body,
                              headers={'Content-Type': 'application/json'})
data = json.load(urllib.request.urlopen(req))
print(data['authorize']['status'])               # 实测输出: OK

注意两点:HTTP 连接无状态,每个 API 请求都要重新携带认证对象(官方文档明示);challenge 按来源连接生成,多线程客户端应"每次请求先取 challenge 再提交"或为每个连接缓存对应 challenge。

2.4 HTTP 头认证与 WebSocket

除请求体携带认证对象外,还可用 HTTP 头方式:Authorization: json {"username":"...","password":"..."}(json 前缀 + 认证对象 JSON)。实测该方式可用;官方文档指出这是 WebSocket API 唯一支持的认证方式(WebSocket 握手后无法再重发请求体,只能靠握手头)。服务端对未授权的 WebSocket 连接会以 WWW-Authenticate: json {...} 头回吐 challenge。

2.5 本机免认证边界

官方文档明示并实测确认:来自本机(localhost)的 API 访问不需要认证。反向代理部署时必须在 config.trustedproxy 中登记代理网段,否则所有经代理的请求都被视为本机来源而跳过认证——这既是便利也是安全边界,管理口因此绝不该直接暴露公网。

三、命令矩阵:以配置域为轴

MistServer 的 API 命令不需要记忆"动词",它的模型是:请求 JSON 里出现哪个配置域成员,就对哪个域执行读(传 null)或写(传对象);特殊动作(增删改的语义变体)有专属命令名。以下命令矩阵来自对服务端命令处理逻辑的源码级梳理 + 逐类实测:

3.1 读命令(传 null 或空对象即读)

命令成员返回实测要点
config: null全局配置域实测返回 protocols/session 模式/weights 全量
streams: null流对象表实测返回三条流及 online 状态
log: null服务日志环形缓冲/api 模式下总是随响应返回
capabilities: null连接器能力清单实测返回 30 个连接器的参数定义(含默认值/可选值),是连接器参数的唯一权威来源
browse: {path: "..."}服务器文件目录浏览供 VoD 选源
load: null服务负载
ui_settings: null界面偏好
streamkeys: null / tags: null流密钥 / 标签

实测读回示例(streams,推流中):

{"cam":  {"name": "cam",  "online": 0, "source": "push://"},
 "live": {"name": "live", "online": 1, "source": "push://"},
 "vod":  {"name": "vod",  "online": 2, "source": "/vod/testvod.mp4", "error": "Available"}}

online 三种实测取值:0 离线(等推流)、1 实时流活跃、2 文件流就绪。

3.2 写命令(配置域赋值)

命令成员语义实测验证
config: {...}增量写全局配置(只覆盖出现的子键)实测 {"config":{"protocols":[...]}}、{"config":{"accesslog":"DEBUG"}} 均即时生效
streams: {流名: {配置}}全量替换流表(CheckStreams 语义)慎用:未出现的流会被移除
addstream: {流名: {配置}}增量添加流实测添加 testapi 成功
deletestream: <流名 | 数组 | 对象>删流(三种形态全支持)实测字符串形态删除 testapi 成功
deletestreamsource: <...>删流并删源文件(返回码区分删到哪一层:源文件/.dtsh 索引)返回值实测为 "1: Source file deleted" 等六种
addprotocol: {连接器实例} | [实例数组]追加协议连接器实测追加 JSON 连接器成功,重同项自动去重
deleteprotocol: {实例}按实例匹配删除(忽略 online 差异)实测删除 JSON 连接器成功
updateprotocol: [旧实例, 新实例]按旧实例匹配整体替换两元素数组形态,源码明示
bandwidth: {...}带宽例外网段
triggers: {...}触发器(webhook 回调)
push_settings: {...} / auto_push主动外推设置与任务
streamkey_add / streamkey_del / addjwks / deletejwks密钥与令牌管理
tags / add_tag / remove_tag流标签

3.3 运维动作命令

命令成员语义
config_backup / config_restore / config_reload配置备份 / 恢复 / 从盘重载
logout使当前连接登出
admin_http_add / admin_http_extend / admin_http_delete / admin_http_list管理 HTTP 输出监听实例的动态增删
trigger_stat / proc_status_update / push_status_update内部状态上报(服务进程 → Controller)

3.4 实测:流生命周期四步

从建流到销毁的完整 API 实测(JSON 体方式,认证成员从略):

# 1. 建流
curl -s 'http://127.0.0.1:4242/api' -H 'Content-Type: application/json' \
  -d '{"addstream":{"testapi":{"name":"testapi","source":"push://"}}}'
# 2. (编码器推流 rtmp://host:1935/testapi/... 后)
# 3. 查询状态
curl -s 'http://127.0.0.1:4242/api' -H 'Content-Type: application/json' \
  -d '{"streams":null}'
# 实测读回: {"testapi":{"name":"testapi","online":1,"source":"push://"},...}
# 4. 删流
curl -s 'http://127.0.0.1:4242/api' -H 'Content-Type: application/json' \
  -d '{"deletestream":"testapi"}'

实测回显按序:{"authorize":{"status":"OK"},...} → 流表含 testapi(推流后 online:1)→ 删除后流表恢复。全程未重启服务、未触碰配置文件——这就是"API 驱动运维"的完整闭环。

四、Web 界面与 API 的关系(取证)

实测把浏览器访问 4242 端口根路径返回的单页应用与 API 行为对照:

  • 界面首启向导的"创建账号"对应 API 的 new_username/new_password(两路实测写回的是同一份 account 表);
  • 界面的 Streams/Protocols/Settings 各页对应 streams/config.protocols/config 域的读写;
  • 界面轮询(实测界面脚本内建 30 秒间隔定时器)用的正是同一套命令;
  • 因此任何界面能做的配置,API 都能做;反之 API 还有界面没有暴露的细粒度命令(如 admin_http_* 动态监听管理)。

这个"界面是 API 的客户端"的设计与 《MediaMTX 1.21.3 API 使用详解》 里 Control API 的纯接口形态不同:MediaMTX 无内嵌界面,MistServer 则是"界面 + API 双前端、单一 JSON 状态后端"。

五、其他接入通道

通道实测/文档依据适用
UDP 本地 API官方文档 Local-only UDP API 章节同机高性能轮询(免 HTTP 开销),仅本机可达
WebSocket API官方文档 Websocket API 章节;实测 4242 口有 /ws 与 /ws/stream/<流名> 路由近实时状态推送(会话/速率变化),认证走握手头(2.4 节)
Prometheus 指标配置 config.prometheus 路径后,管理口按路径暴露监控接入,属只读旁路

本篇聚焦 HTTP API 主通道;UDP/WebSocket 通道的命令语义与 HTTP 一致,差异只在传输与认证载体。

六、错误处理与安全

6.1 错误形态实测

场景实测响应
未认证请求业务命令只返回 {"authorize":{"status":"CHALL","challenge":"..."}}
认证密码错误服务端日志记录 AUTH: Failed login attempt root from <IP>(实测捕获),响应仍 CHALL
写命令格式不当对应命令在日志报 FAIL/WARN(如 updateprotocol 非两元素数组报 Cannot parse updateprotocol call)
请求 JSON 非对象管理口按"无效请求"返回 Web 界面单页(除非路径是 /api、/api2)

6.2 安全要点

  1. 管理口不暴露公网;反向代理场景必配 trustedproxy(否则代理后的请求全被当本机免认证,2.5 节);
  2. 初始建号(new_password 明文)只该发生在受信内网的首启环节;
  3. --account 启动参数传明文会出现在进程列表,优先用首启向导或 API 建号;
  4. 持久层文件里是密码 MD5,泄露该文件等于泄露管理面——纳入备份的同时控制读取权限。

七、排障实录

实录一:"返回 OK 但配置没变"。 现象:POST 表单编码(application/x-www-form-urlencoded)提交 command=<JSON>,认证通过、响应 200,但所有写成员(addstream/config/protocols)不生效。定位:用 JSON 请求体(Content-Type: application/json)重放同一命令立即生效;GET query 方式亦生效。结论:服务端对表单编码的 command 参数解析不完整(实测行为),程序化对接一律 JSON 体。这一坑的隐蔽性在于认证恰好成功,极易误判为"权限问题"或"配置被覆盖"。

实录二:capabilities 是参数权威,别手拼。 连接器实例的参数名/类型/默认值应以 capabilities 命令读回为准(30 个连接器全量实测可读)。实测中按记忆手写 {"connector":"TSSRT","port":"8889"} 可行,但 SRT 的 passphrase/sockopts 等参数拼写与取值范围查 capabilities 最稳——它就是界面下拉框的数据源。

实录三:stream online 与 connector online 是两套状态。 streams.<名>.online 是流级状态(0/1/2,见 3.1 节);config.protocols[].online 是连接器级状态(1 = 监听已拉起)。排障时先看连接器 online(推流不通的常见根因是 RTMP 连接器压根没启用——首启向导跳过协议步的部署会踩),再看流 online(多为推流地址流名不匹配)。

实录四:json 元数据路径在 3.12 的变化。 HTTP 口流元数据接口,老文档的 json_<流名>.json 路径实测失败(服务端把 json_live 整体当流名查,日志 Could not get stream 'json_live' config!);实测可用路径是 /<流名>.json。依赖该接口做监控取数的脚本升级 3.x 时必须核对。

八、命令速查卡

# 读
config:null  streams:null  log:null  capabilities:null  browse:{path}
# 流写
addstream:{名:{name,source}}   deletestream:<名|[]>   streams:{...全量替换}
# 连接器写
addprotocol:{connector,port,...}   deleteprotocol:{connector,...}   updateprotocol:[旧,新]
# 全局写
config:{accesslog|debug|protocols|sessionViewerMode|trustedproxy|weights|...}
# 运维
config_backup  config_reload  logout  admin_http_add/delete/list
# 认证
authorize:{username,password:MD5(MD5(pwd)+challenge)}
          {new_username,new_password}   # 仅 NOACC 时

九、参考链接