openPLC REST API 参考(英译中)

REST API 参考

概述

OpenPLC Runtime v4 提供了一个内部 REST API,通过 HTTPS 协议提供服务,供 OpenPLC Editor 桌面应用程序使用。该 API 并非设计为供最终用户直接交互,但可用于高级集成或诊断。

所有端点均可通过 https://<主机>:8443/api/<端点> 地址访问。

基础 URL

复制代码
https://localhost:8443/api

认证

运行时使用基于 JWT 的认证:

  1. 首次创建用户POST /api/create-user(创建第一个用户无需认证)
  2. 登录POST /api/login 返回 JWT 访问令牌
  3. 认证请求 :所有其他端点都需要 Authorization: Bearer <令牌> 请求头

注意:OpenPLC Editor 会自动处理认证。高级集成者必须手动实现认证流程。

通用响应格式

所有 API 响应均为 JSON 对象。成功响应通常包含一个 status 字段,而错误响应则包含描述性的错误消息。

认证端点

创建用户

创建新的用户账户。第一个用户可以在没有认证的情况下创建。后续创建用户需要 JWT 认证。

请求:

http 复制代码
POST /api/create-user
Content-Type: application/json

{
  "username": "admin",
  "password": "your_password",
  "role": "admin"
}

响应(成功):

json 复制代码
{
  "msg": "用户已创建",
  "id": 1
}

响应(错误):

json 复制代码
{
  "msg": "用户名已存在"
}

状态码:

  • 201 Created - 用户创建成功
  • 400 Bad Request - 缺少用户名或密码
  • 401 Unauthorized - 用户已存在且未提供有效的 JWT
  • 409 Conflict - 用户名已存在

登录

进行身份验证并获取 JWT 访问令牌。

请求:

http 复制代码
POST /api/login
Content-Type: application/json

{
  "username": "admin",
  "password": "your_password"
}

响应(成功):

json 复制代码
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

响应(错误):

json 复制代码
"用户名或密码错误"

状态码:

  • 200 OK - 登录成功
  • 401 Unauthorized - 凭据无效
  • 500 Internal Server Error - 数据库错误

注意事项:

  • 访问令牌应包含在所有后续请求的 Authorization: Bearer <令牌> 请求头中
  • 令牌在配置的持续时间(默认:24 小时)后过期

PLC 控制端点

所有 PLC 控制端点都需要 JWT 认证。

启动 PLC

启动 PLC 程序执行。

请求:

http 复制代码
GET /api/start-plc
Authorization: Bearer <令牌>

响应:

json 复制代码
{
  "status": "PLC 启动成功"
}

可能的 Status 值:

  • "PLC 启动成功" - PLC 已切换到 RUNNING 状态
  • "PLC 已在运行" - PLC 已处于 RUNNING 状态
  • "未加载 PLC 程序" - 没有可用的已编译程序
  • "运行时无响应" - 运行时进程无响应

停止 PLC

停止 PLC 程序执行。

请求:

http 复制代码
GET /api/stop-plc
Authorization: Bearer <令牌>

响应:

json 复制代码
{
  "status": "PLC 停止成功"
}

可能的 Status 值:

  • "PLC 停止成功" - PLC 已切换到 STOPPED 状态
  • "PLC 已停止" - PLC 已处于 STOPPED 状态
  • "运行时无响应" - 运行时进程无响应

获取 PLC 状态

查询当前的 PLC 状态。

请求:

http 复制代码
GET /api/status
Authorization: Bearer <令牌>

响应:

json 复制代码
{
  "status": "RUNNING"
}

可能的 Status 值:

  • "EMPTY" - 未加载 PLC 程序
  • "INIT" - 程序已加载,正在初始化
  • "RUNNING" - 正在主动执行扫描周期
  • "STOPPED" - 程序已加载但未执行
  • "ERROR" - 可恢复的错误状态
  • "运行时无响应" - 运行时进程无响应

运行时 Ping

检查运行时进程是否响应。

请求:

http 复制代码
GET /api/ping
Authorization: Bearer <令牌>

响应:

json 复制代码
{
  "status": "pong"
}

可能的 Status 值:

  • "pong" - 运行时进程响应正常
  • null - 运行时进程无响应

程序管理端点

上传 PLC 程序

上传一个包含由 OpenPLC Editor v4 生成的 PLC 程序源文件的 ZIP 文件。

请求:

http 复制代码
POST /api/upload-file
Authorization: Bearer <令牌>
Content-Type: multipart/form-data

file: <ZIP 文件>

成功响应:

json 复制代码
{
  "UploadFileFail": "",
  "CompilationStatus": "COMPILING"
}

错误响应:

json 复制代码
{
  "UploadFileFail": "错误消息",
  "CompilationStatus": "FAILED"
}

编译状态值:

  • "IDLE" - 无构建进行中
  • "UNZIPPING" - 正在解压 ZIP 文件
  • "COMPILING" - 正在运行编译脚本
  • "SUCCESS" - 构建成功完成
  • "FAILED" - 构建失败

错误条件:

  • 请求中没有文件
  • 文件过大(>10 MB 每文件,>50 MB 总计)
  • ZIP 验证失败(路径遍历、压缩率、不允许的扩展名)
  • 另一个编译正在进行中
  • 文件系统错误

注意事项:

  • 编译在后台线程中异步运行
  • 使用 /api/compilation-status 端点来监视进度
  • PLC 在编译期间会自动停止
  • OpenPLC Editor 在本地编译程序(JSON → XML → ST → C),并将源文件作为 ZIP 上传

获取编译状态

查询最近一次编译的状态。

请求:

http 复制代码
GET /api/compilation-status
Authorization: Bearer <令牌>

响应:

json 复制代码
{
  "status": "SUCCESS",
  "logs": [
    "[INFO] 开始编译",
    "[INFO] 正在编译 Config0.c...",
    "[INFO] 正在编译 Res0.c...",
    "[INFO] 正在编译 debug.c...",
    "[INFO] 正在编译 glueVars.c...",
    "[INFO] 正在编译 c_blocks_code.cpp...",
    "[INFO] 正在编译共享库...",
    "[INFO] 构建成功完成"
  ],
  "exit_code": 0
}

响应字段:

  • status - 当前构建状态(IDLE, UNZIPPING, COMPILING, SUCCESS, FAILED)
  • logs - 来自构建过程的日志消息数组
  • exit_code - 编译脚本的退出代码(0 = 成功,非零 = 错误,null = 进行中)

注意事项:

  • OpenPLC Editor 轮询此端点以监视编译进度
  • 日志在编译期间累积
  • 错误消息以 [ERROR] 为前缀
  • 退出代码在编译完成前为 null

获取运行时日志

从 PLC 运行时进程检索日志。

请求:

http 复制代码
GET /api/runtime-logs
GET /api/runtime-logs?id=<最小_ID>
GET /api/runtime-logs?level=<日志等级>
Authorization: Bearer <令牌>

查询参数:

  • id (可选) - 要检索的最小日志 ID(用于分页)
  • level (可选) - 按日志等级过滤(DEBUG, INFO, WARNING, ERROR)

响应:

json 复制代码
{
  "runtime-logs": [
    {
      "id": 1,
      "timestamp": "2024-01-01T12:00:00.000Z",
      "level": "INFO",
      "message": "PLC 启动成功"
    },
    {
      "id": 2,
      "timestamp": "2024-01-01T12:00:05.000Z",
      "level": "DEBUG",
      "message": "扫描计数: 100"
    }
  ]
}

日志等级:

  • DEBUG - 详细的诊断信息
  • INFO - 一般信息性消息
  • WARNING - 警告消息
  • ERROR - 错误消息

错误处理

HTTP 状态码

  • 200 OK - 请求成功
  • 201 Created - 资源创建成功
  • 400 Bad Request - 请求参数无效
  • 401 Unauthorized - 需要认证或令牌无效
  • 409 Conflict - 资源冲突(例如,用户名已存在)
  • 500 Internal Server Error - 服务器错误

错误响应格式

json 复制代码
{
  "error": "错误消息描述"
}

或对于某些端点:

json 复制代码
{
  "msg": "错误消息描述"
}

使用示例

完整的认证流程

cURL 示例:

bash 复制代码
# 步骤 1:创建第一个用户
curl -k -X POST https://localhost:8443/api/create-user \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin123","role":"admin"}'

# 步骤 2:登录并获取 JWT 令牌
TOKEN=$(curl -k -X POST https://localhost:8443/api/login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin123"}' \
  | jq -r '.access_token')

echo "令牌: $TOKEN"

# 步骤 3:使用令牌进行认证请求

# 获取 PLC 状态
curl -k https://localhost:8443/api/status \
  -H "Authorization: Bearer $TOKEN"

# 启动 PLC
curl -k https://localhost:8443/api/start-plc \
  -H "Authorization: Bearer $TOKEN"

# 停止 PLC
curl -k https://localhost:8443/api/stop-plc \
  -H "Authorization: Bearer $TOKEN"

# 上传程序
curl -k -X POST https://localhost:8443/api/upload-file \
  -H "Authorization: Bearer $TOKEN" \
  -F "file=@program.zip"

# 获取编译状态
curl -k https://localhost:8443/api/compilation-status \
  -H "Authorization: Bearer $TOKEN"

# 获取运行时日志
curl -k https://localhost:8443/api/runtime-logs \
  -H "Authorization: Bearer $TOKEN"

# Ping 运行时
curl -k https://localhost:8443/api/ping \
  -H "Authorization: Bearer $TOKEN"

注意: -k 标志用于绕过自签名证书的验证。

Python 示例:

python 复制代码
import requests
import urllib3
import time

# 禁用自签名证书的 SSL 警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

base_url = "https://localhost:8443/api"

# 步骤 1:创建第一个用户(无需认证)
response = requests.post(
    f"{base_url}/create-user",
    json={"username": "admin", "password": "admin123", "role": "admin"},
    verify=False
)
print(f"用户创建: {response.json()}")

# 步骤 2:登录获取 JWT 令牌
response = requests.post(
    f"{base_url}/login",
    json={"username": "admin", "password": "admin123"},
    verify=False
)
token = response.json()["access_token"]
print(f"接收到的令牌: {token[:50]}...")

# 步骤 3:使用令牌进行认证请求
headers = {"Authorization": f"Bearer {token}"}

# 获取 PLC 状态
response = requests.get(f"{base_url}/status", headers=headers, verify=False)
print(f"PLC 状态: {response.json()}")

# 启动 PLC
response = requests.get(f"{base_url}/start-plc", headers=headers, verify=False)
print(f"启动 PLC: {response.json()}")

# 上传程序
with open("program.zip", "rb") as f:
    files = {"file": f}
    response = requests.post(
        f"{base_url}/upload-file",
        files=files,
        headers=headers,
        verify=False
    )
    print(f"上传: {response.json()}")

# 监视编译
while True:
    response = requests.get(
        f"{base_url}/compilation-status",
        headers=headers,
        verify=False
    )
    status = response.json()
    print(f"编译状态: {status['status']}")

    if status["status"] in ["SUCCESS", "FAILED"]:
        print("编译日志:")
        for log in status["logs"]:
            print(f"  {log}")
        break

    time.sleep(1)

JavaScript/Node.js 示例:

javascript 复制代码
const https = require('https');
const fetch = require('node-fetch');
const FormData = require('form-data');
const fs = require('fs');

// 禁用自签名证书的 SSL 验证
const agent = new https.Agent({ rejectUnauthorized: false });
const baseUrl = "https://localhost:8443/api";

async function main() {
  // 步骤 1:创建第一个用户
  let response = await fetch(`${baseUrl}/create-user`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      username: 'admin',
      password: 'admin123',
      role: 'admin'
    }),
    agent
  });
  console.log('用户创建:', await response.json());

  // 步骤 2:登录获取 JWT 令牌
  response = await fetch(`${baseUrl}/login`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      username: 'admin',
      password: 'admin123'
    }),
    agent
  });
  const { access_token } = await response.json();
  console.log('接收到的令牌:', access_token.substring(0, 50) + '...');

  // 步骤 3:使用令牌进行认证请求
  const headers = { 'Authorization': `Bearer ${access_token}` };

  // 获取 PLC 状态
  response = await fetch(`${baseUrl}/status`, { headers, agent });
  console.log('PLC 状态:', await response.json());

  // 启动 PLC
  response = await fetch(`${baseUrl}/start-plc`, { headers, agent });
  console.log('启动 PLC:', await response.json());

  // 上传程序
  const formData = new FormData();
  formData.append('file', fs.createReadStream('program.zip'));

  response = await fetch(`${baseUrl}/upload-file`, {
    method: 'POST',
    headers: { ...headers },
    body: formData,
    agent
  });
  console.log('上传:', await response.json());

  // 监视编译
  while (true) {
    response = await fetch(`${baseUrl}/compilation-status`, { headers, agent });
    const status = await response.json();
    console.log('编译状态:', status.status);

    if (status.status === 'SUCCESS' || status.status === 'FAILED') {
      console.log('编译日志:');
      status.logs.forEach(log => console.log('  ' + log));
      break;
    }

    await new Promise(resolve => setTimeout(resolve, 1000));
  }
}

main();

速率限制

目前没有强制执行速率限制。但是,请注意:

  • 一次只能运行一个编译
  • 频繁的启动/停止命令可能会导致状态转换问题
  • 日志查询在大容量日志时可能占用大量资源

安全注意事项

  1. 仅限 HTTPS:所有通信必须使用 HTTPS(端口 8443)
  2. JWT 认证:除首次创建用户和登录外,所有端点都需要 JWT 认证
  3. 自签名证书:默认安装使用自签名证书(OpenPLC Editor 会自动处理)
  4. 文件上传验证:ZIP 文件在解压前会经过全面的安全检查
  5. 大小限制:文件大小受到限制以防止资源耗尽(10 MB 每文件,50 MB 总计)
  6. 路径验证:所有文件路径都经过验证以防止遍历攻击
  7. 密码安全:密码使用 PBKDF2-SHA256(600,000 次迭代)、盐值和胡椒值进行哈希处理

WebSocket 调试接口

对于实时调试和变量检查,OpenPLC Editor 使用位于 https://<主机>:8443/api/debug 的 WebSocket 接口。详情请参阅 调试协议

相关文档

相关推荐
m0_736919104 小时前
模板编译期图算法
开发语言·c++·算法
玖釉-4 小时前
深入浅出:渲染管线中的抗锯齿技术全景解析
c++·windows·图形渲染
【心态好不摆烂】4 小时前
C++入门基础:从 “这是啥?” 到 “好像有点懂了”
开发语言·c++
dyyx1114 小时前
基于C++的操作系统开发
开发语言·c++·算法
AutumnorLiuu4 小时前
C++并发编程学习(一)——线程基础
开发语言·c++·学习
m0_736919104 小时前
C++安全编程指南
开发语言·c++·算法
才盛智能科技4 小时前
歪麦霸王餐&元K(才盛云)签订战略合作
大数据·人工智能·物联网·自助ktv系统·才盛云
阿猿收手吧!4 小时前
C++ std::lock与std::scoped_lock深度解析:从死锁解决到安全实践
开发语言·c++
深蓝电商API4 小时前
async/await与多进程结合的混合爬虫架构
爬虫·架构
2301_790300965 小时前
C++符号混淆技术
开发语言·c++·算法