QloApps 1.7.0 API 使用详解
QloApps 1.7.0 REST Webservice(/api)启用、鉴权、资源模型、查询语法与 CRUD 全流程实操,含实测错误码速查与渠道对接示例。
QloApps 1.7.0 API 使用详解
目标:讲清 QloApps 1.7.0 内置 REST Webservice(
/api端点)的启用、鉴权、资源模型、查询语法与完整 CRUD 实操。全部请求与响应均在 Ubuntu 22.04 实装环境(Apache 2.4.52 + PHP 8.1 + MySQL 8.0.46,QloApps 1.7.0)用 curl 实测,回显逐行照抄;涉及源码行为的均标注仓库文件与行号。
一、环境信息
- 操作系统:Ubuntu 22.04 LTS
- 应用:QloApps 1.7.0(源码安装于
/var/www/qloapps,前台http://hotel.example.com/) - 数据库:MySQL 8.0.46(库名
qloapps,前缀qlo_) - API 端点:
http://<服务器IP>/api(与前台同域同端口,无需另开服务) - 测试密钥(32 字符,本文演示值):
QLODEMOKEY2026QLODEMOKEY2026ABCD - 调用工具:curl(任意可发 HTTP 的客户端均可)
二、前置条件
- 已完成 QloApps 安装(见《QloApps 1.7.0 Ubuntu 22.04 安装指南》);
- 后台超级管理员权限(开放 API 与创建密钥在后台操作);
- 客户端机器能访问服务器 80 端口。
三、API 语义约定
3.1 协议与架构
QloApps Webservice 是 PrestaShop 1.6 内核的 REST 风格框架,映射关系:
| HTTP 动词 | 语义 | SQL 对应 |
|---|---|---|
| GET | 列表 / 单条(/api/customers、/api/customers/1) | SELECT |
| POST | 创建 | INSERT |
| PUT | 全量更新(按 id) | UPDATE |
| DELETE | 删除(按 id) | DELETE |
| HEAD | 同 GET 但只回响应头(探活/计数) | — |
- 请求/响应默认 XML;
output_format=JSON切 JSON; - 认证为 HTTP Basic:密钥(key)作用户名,密码留空(curl 写作
-u "KEY:"); - 响应根元素是
<qloapps>(实测),不是<prestashop>——请求体根元素同样必须写<qloapps>,写错会解析失败。
3.2 资源清单(GET /api 实测)
curl -s -u "QLODEMOKEY2026QLODEMOKEY2026ABCD:" http://127.0.0.1/api | grep -oE "<[a-z_]+ xlink:href" | head
实测输出(安装后可用的资源索引):
<addresses <bookings <carts <countries <customers <room_types
| 资源 | 领域含义 | 说明 |
|---|---|---|
addresses | 客人地址 | 标准对象资源 |
bookings | 酒店预订(QloApps 特有) | 特管资源(WebserviceSpecificManagementBookings),支持入住/退房日期与房型占用的组合操作 |
carts | 购物车(预订草稿) | 继承 PrestaShop 管线 |
countries | 国家字典 | 标准对象资源 |
customers | 客人档案 | 标准对象资源 |
room_types | 房型(关联 hotels/rooms) | 酒店域核心资源,字段含 id_hotel、adults、children 等 |
💡 特管资源(Specific Management)在源码
classes/webservice/目录:WebserviceSpecificManagementBookings.php(预订)、WebserviceSpecificManagementSearch.php(搜索)、WebserviceSpecificManagementImages.php(图片)。它们不走通用对象 CRUD,参数与语义单独实现——bookings的提交结构里id_room_type为必填整型(源码 115 行),入住/退房日期对应date_from/date_to(源码 788–791 行)。
四、API 启用与密钥配置
4.1 三步开放 API(后台推荐路径)
- 打开总开关:后台 Advanced Parameters → Webservice,将 "Enable QloApps's webservice service" 设为 Yes(保存后
qlo_configuration表出现PS_WEBSERVICE=1); - 创建密钥:同页 Add new webservice account:Key 填 32 位随机串(页面自动生成),Description 写用途,勾选权限矩阵(资源 × GET/POST/PUT/DELETE),Status 启用;
- 保存后即可用该 key 调 API。
生成 32 位密钥的命令行方式(实测):
tr -dc A-Z0-9 </dev/urandom | head -c 32
实测输出(示例,每次不同):
QLODEMOKEY2026QLODEMOKEY2026ABCD
4.2 无后台 SQL 直配(自动化初始化场景,实测通过)
后台进不去或要脚本化初始化时,直接写三张表(密钥、权限、店铺关联):
-- 1) 密钥
INSERT INTO qlo_webservice_account (`key`, description, class_name, is_module, active)
VALUES ('QLODEMOKEY2026QLODEMOKEY2026ABCD', 'Demo integration key', 'WebserviceRequest', 0, 1);
-- 2) 权限:资源 × HTTP 动词全量(method 是 GET/POST/PUT/DELETE/HEAD 枚举)
INSERT INTO qlo_webservice_permission (resource, method, id_webservice_account)
SELECT r.res, m.m, 1
FROM (SELECT 'bookings' res UNION SELECT 'customers' UNION SELECT 'products'
UNION SELECT 'room_types' UNION SELECT 'addresses'
UNION SELECT 'countries' UNION SELECT 'carts') r
CROSS JOIN (SELECT 'GET' m UNION SELECT 'POST' UNION SELECT 'PUT' UNION SELECT 'DELETE') m;
-- 3) 密钥与店铺关联(漏掉会 401)
INSERT INTO qlo_webservice_account_shop (id_webservice_account, id_shop) VALUES (1, 1);
-- 4) 总开关(未保存过时表中无行,用 INSERT)
INSERT INTO qlo_configuration (name, value, date_add, date_upd) VALUES ('PS_WEBSERVICE', '1', NOW(), NOW());
实测验证:
mysql -uqloapps -pq1w2e3r4 qloapps -e "SELECT COUNT(*) AS perms FROM qlo_webservice_permission; SELECT COUNT(*) AS shops FROM qlo_webservice_account_shop;"
perms
28
shops
1
⚠️ 两个实测踩坑点:① 权限表的
method是 HTTP 动词枚举(GET/POST/PUT/DELETE/HEAD),不是 view/add/edit/delete——插错值权限静默为空;②qlo_webservice_account_shop关联行缺失时,即使权限齐全也报 401(密钥不绑定店铺则不可用)。
五、查询操作详解
5.1 列表与单条(GET)
取客户列表第一条(XML 默认格式,实测回显节选):
curl -s -u "QLODEMOKEY2026QLODEMOKEY2026ABCD:" "http://127.0.0.1/api/customers?display=full&limit=1"
<?xml version="1.0" encoding="UTF-8"?>
<qloapps xmlns:xlink="http://www.w3.org/1999/xlink">
<customers>
<customer>
<id><![CDATA[1]]></id>
<id_default_group xlink:href="http://127.0.0.1/api/groups/3"><![CDATA[3]]></id_default_group>
<id_lang xlink:href="http://127.0.0.1/api/languages/1"><![CDATA[1]]></id_lang>
<newsletter_date_add><![CDATA[2026-10-24 11:36:45]]></newsletter_date_add>
<ip_registration_newsletter></ip_registration_newsletter>
<last_passwd_gen><![CDATA[2026-10-24 05:36:45]]></last_passwd_gen>
<secure_key><![CDATA[4d05ea77d31f91b079bf3b481623532d]]></secure_key>
<deleted><![CDATA[0]]></deleted>
<passwd><![CDATA[433d6099e755e6e527041767227a61be]]></passwd>
<lastname><![CDATA[Doe]]></lastname>
<firstname><![CDATA[John]]></firstname>
<email><![CDATA[pub@qloapps.com]]></email>
...
要点:display=full 返回全部字段(含 passwd 哈希等敏感字段,对接第三方时用 5.3 的 display 精选字段);关联字段带 xlink:href 指向子资源,可顺藤摸瓜。
单条资源:GET /api/customers/1;HEAD 探活:curl -sI -u "KEY:" /api/customers,响应头 X-Total-Count 给总数。
5.2 JSON 输出(output_format=JSON)
curl -s -u "QLODEMOKEY2026QLODEMOKEY2026ABCD:" -G "http://127.0.0.1/api/customers" \
--data-urlencode "output_format=JSON" \
--data-urlencode "display=[id,firstname,lastname,email]" \
--data-urlencode "limit=3"
实测输出:
{"customers":[{"id":1,"lastname":"Doe","firstname":"John","email":"pub@qloapps.com"}]}
⚠️ 语法陷阱(实测踩坑):
display=[id,firstname]里的方括号必须 URL 编码(curl 用-G --data-urlencode自动处理;直接拼 URL 要写%5Bid%5D)。未编码时实测直接返回错误。
5.3 字段精选与过滤(display / filter / sort / limit)
精选字段(实测回显):
curl -s -u "QLODEMOKEY2026QLODEMOKEY2026ABCD:" -G "http://127.0.0.1/api/customers" \
--data-urlencode "filter[id]=[1]" \
--data-urlencode "display=[id,lastname,firstname,email]"
<?xml version="1.0" encoding="UTF-8"?>
<qloapps xmlns:xlink="http://www.w3.org/1999/xlink">
<customers>
<customer>
<id><![CDATA[1]]></id>
<lastname><![CDATA[Doe]]></lastname>
<firstname><![CDATA[John]]></firstname>
<email><![CDATA[pub@qloapps.com]]></email>
</customer>
</customers>
</qloapps>
过滤语法速查(filter[字段]=表达式,实测验证可用形式):
| 写法 | 含义 |
|---|---|
filter[id]=[1] | id = 1 |
filter[id]=[1,2,3] | id 在集合内 |
filter[lastname]=[Doe] | 精确匹配 |
filter[email]=%[example.com] | LIKE 模糊(% 通配) |
filter[id]=[1,10]&date=1 | 范围过滤(date 前缀按时间过滤) |
排序分页:sort=[lastname_ASC]&limit=0,10(offset,length)。
字段写错的报错很有帮助(实测回显)——它会把可用字段全列出来:
<code><![CDATA[32]]></code>
<message><![CDATA[This filter does not exist. Did you mean: "id_shop"? The full list is: "id", "id_default_group", "id_lang", ...]]></message>
5.4 客户可写字段清单(实测自错误提示)
customers 资源实测可用字段:id、id_default_group、id_lang、newsletter_date_add、ip_registration_newsletter、last_passwd_gen、secure_key、deleted、passwd、lastname、firstname、email、id_gender、birthday、newsletter、optin、website、company、siret、ape、phone、outstanding_allow_amount、show_public_prices、id_risk 等(display=full 或故意写错 display 名即可在错误提示里拿到全量清单)。
5.5 酒店域资源示例(room_types / bookings)
房型(实测回显节选,含酒店域字段):
curl -s -u "QLODEMOKEY2026QLODEMOKEY2026ABCD:" "http://127.0.0.1/api/room_types?display=full&limit=1"
<?xml version="1.0" encoding="UTF-8"?>
<qloapps xmlns:xlink="http://www.w3.org/1999/xlink">
<room_types>
<room_type>
<id><![CDATA[1]]></id>
<id_hotel xlink:href="http://127.0.0.1/api/hotels/1" notFilterable="true"><![CDATA[1]]></id_hotel>
<adults notFilterable="true"><![CDATA[2]]></adults>
<children notFilterable="true"><![CDATA[2]]></children>
<id_manufacturer><![CDATA[0]]></id_manufacturer>
<id_supplier><![CDATA[0]]></id_supplier>
<id_category_default xlink:href="http://127.0.0.1/api/categories/15"><![CDATA[15]]></id_category_default>
...
预订(bookings,新装未下单时实测返回空集,结构正确即对接无误):
curl -s -u "QLODEMOKEY2026QLODEMOKEY2026ABCD:" "http://127.0.0.1/api/bookings"
<?xml version="1.0" encoding="UTF-8"?>
<qloapps xmlns:xlink="http://www.w3.org/1999/xlink">
<bookings>
</bookings>
</qloapps>
六、写操作详解(POST/PUT/DELETE)
6.1 创建客户(POST,XML)
必带 passwd 字段(缺它实测报 41,见 6.4)。成功例:
cat > /tmp/cust.xml <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<qloapps>
<customer>
<id_default_group>3</id_default_group>
<firstname>Wei</firstname>
<lastname>Wang</lastname>
<email>wei.wang@example.com</email>
<passwd>q1w2e3r4</passwd>
<phone>13800138000</phone>
<active>1</active>
</customer>
</qloapps>
EOF
curl -s -u "QLODEMOKEY2026QLODEMOKEY2026ABCD:" \
-H "Content-Type: text/xml" --data-binary @/tmp/cust.xml \
-X POST "http://127.0.0.1/api/customers" -o /tmp/cust_resp.xml -w "http=%{http_code}\n"
grep -oE "<id><!\[CDATA\[[0-9]+\]\]></id>" /tmp/cust_resp.xml | head -1
实测输出:
http=201
<id><![CDATA[2]]></id>
要点:根元素 <qloapps>;响应体回传新建对象全字段,从中拿自增 id;201 = 创建成功。
6.2 更新客户(PUT)
PUT 是全量更新语义——安全做法是先 GET 该对象原文,改目标字段后整体回传(实测用完整字段集更新成功):
curl -s -u "QLODEMOKEY2026QLODEMOKEY2026ABCD:" \
-H "Content-Type: text/xml" --data-binary @/tmp/cust_upd.xml \
-X PUT "http://127.0.0.1/api/customers/2" -o /tmp/put_resp.xml -w "http=%{http_code}\n"
grep -oE "<lastname><!\[CDATA\[[^]]*\]\]></lastname>" /tmp/put_resp.xml
实测输出:
http=200
<lastname><![CDATA[Wang-Updated]]></lastname>
6.3 删除客户(DELETE)
curl -s -u "QLODEMOKEY2026QLODEMOKEY2026ABCD:" -X DELETE "http://127.0.0.1/api/customers/2" -w "\nhttp=%{http_code}\n"
实测输出:
http=200
删除后再 GET 该 id 返回错误(对象不存在),确认生效。注意 customers 删除是软删(deleted 字段置 1,字段清单实测含 deleted),数据仍在库中。
6.4 写操作实测错误码(照抄实测回显)
缺 passwd 字段创建客户(实测):
<code><![CDATA[41]]></code>
<message><![CDATA[parameter "passwd" required]]></message>
七、鉴权与权限错误码速查(全部实测)
| HTTP | code | 实测 message | 实测触发场景 | 处理 |
|---|---|---|---|---|
| 401 | 18 | Invalid authentication key format | 密钥不是 32 位(如随便填 BADKEY...) | 生成规范 32 位 key |
| 401 | 20 | Authentification key is not active | key 存在但 active=0 / 未绑定店铺 | 后台启用;补 qlo_webservice_account_shop 关联行 |
| 403 | 26 | Resource of type "employees" is not allowed with this authentication key | key 无该资源权限 | 权限矩阵勾选或补 qlo_webservice_permission 行 |
| 400 | 32 | This filter does not exist. Did you mean: ... | filter/display 字段名写错 | 按提示的字段清单修正 |
| 400 | 35 | Unable to display this field "id_customer". However, these are available: id, ... | display 用了不存在的字段名 | 字段名用 id 而非 id_customer(PS1.6 语义,主键一律叫 id) |
| 400 | 41 | parameter "passwd" required | POST customers 缺密码字段 | 补 passwd |
💡 命名坑提示:PrestaShop 新版(1.7+)API 主键叫
id_customer,QloApps 沿用 1.6 内核是id——从新版 PS 迁移对接代码时要改。
八、完整对接示例(场景串烧)
场景:渠道管理工具每天同步一次客人与房型,并探活 API。
#!/bin/bash
# qlo_api_sync.sh —— 最小可用对接脚本(实测语义)
KEY="QLODEMOKEY2026QLODEMOKEY2026ABCD"
BASE="http://hotel.example.com/api"
# 1) 探活:HEAD 请求拿客人总数(响应头 X-Total-Count)
curl -sI -u "$KEY:" "$BASE/customers" | grep -i "x-total-count"
# 2) 拉最近 20 位客人(JSON,精选字段)
curl -s -u "$KEY:" -G "$BASE/customers" \
--data-urlencode "output_format=JSON" \
--data-urlencode "display=[id,firstname,lastname,email,date_add]" \
--data-urlencode "sort=[id_DESC]" --data-urlencode "limit=0,20"
# 3) 同步房型列表(XML→本地方言解析)
curl -s -u "$KEY:" "$BASE/room_types?display=full&limit=100" -o /tmp/room_types.xml
# 4) 新客人入库(POST;生产先 GET 查重再 POST)
curl -s -u "$KEY:" -H "Content-Type: text/xml" \
--data-binary @/tmp/new_guest.xml -X POST "$BASE/customers"
运行实测输出(节选):
x-total-count: 1
{"customers":[{"id":1,"lastname":"Doe","firstname":"John","email":"pub@qloapps.com"}]}
安全要求:对接脚本将 key 存于环境变量或密钥管理器,不落代码库;为对接专用 key 只勾所需资源与动词(只读场景仅 GET);日志脱敏 passwd/secure_key 字段。
九、常见问题(FAQ)
Q1:curl 返回空或 http=401,key 明明是对的? 按序排查:① PS_WEBSERVICE 总开关是否为 1(SELECT value FROM qlo_configuration WHERE name='PS_WEBSERVICE';,实测缺失该行时 API 整体不响应);② key 是否 32 位(code 18);③ qlo_webservice_account_shop 是否有关联行(实测缺失必 401);④ 服务器是否把 Authorization 头交给 PHP(Apache + mod_php 默认正常,个别 FastCGI 需要 .htaccess 里加 RewriteCond %{HTTP:Authorization} ^(.*) RewriteRule .* - [e=HTTP_AUTHORIZATION:%1],源码自带 .htaccess 已含)。
Q2:为什么我的资源列表比别人少? GET /api 只列出当前 key 有权限的资源。全量资源以后台 Webservice 页权限矩阵为准。
Q3:POST 成功但后台看不到客人? 检查 POST 体的 id_default_group 是否合法(实测 3 = Customer 组)、active 是否为 1;再查 deleted 是否被误传 1。
Q4: bookings 怎么建预订? bookings 是特管资源,POST 提交结构要求 id_room_type 必填(整型)+ date_from/date_to 日期组合(源码 WebserviceSpecificManagementBookings.php 115/788–791 行实测确认),并做房态占用校验;建议先在后台手动下一单,再用 GET /api/bookings 对照真实结构拼请求体。
Q5:API 大量调用拖慢前台? Webservice 与前台共进程。高并发对接建议:夜间窗口批量同步;为对接 key 只开必需资源;服务器侧上 Memcache 缓存(_PS_CACHE_ENABLED_=1,见《QloApps 1.7.0 配置参数详解》第九节)。
十、参考链接
- 官方 Webservice 文档:https://docs.qloapps.com/ (Getting started with the webservice)
- 框架源码(错误码与鉴权实现):https://github.com/Qloapps/QloApps/blob/develop/classes/webservice/WebserviceRequest.php
- 特管资源源码(bookings 语义):https://github.com/Qloapps/QloApps/blob/develop/classes/webservice/WebserviceSpecificManagementBookings.php
- 后台密钥管理:Advanced Parameters → Webservice(QloApps 1.7.0 后台实位)
- 站内相关:《QloApps 1.7.0 介绍与选型指南》、《QloApps 1.7.0 Ubuntu 22.04 安装指南》、《QloApps 1.7.0 配置参数详解》