mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-11-07 09:47:23 +00:00
fix(billing): 插件 HTTP 路由按操作拆路径 + 正确解析请求体
- 内核插件路由冲突仲裁按**路径**判重(不看 method),同一路径挂 4 个 method 会被
当成 4 个插件抢同一路径 ⇒ 规则 API 不可用。拆成 /rules(GET)、/rules/replace
(PUT)、/rules/add(POST)、/rules/remove(DELETE)。
- 插件 HTTP 分发交给 handler 的是**整个请求表**(body 是原始字符串),而直调导出
拿到的是参数表;此前 PUT 把请求信封当成规则写进了 billing.json,规则全丢、价格表
清空。新增 reqData() 统一解出 JSON 载荷。
- 生产复验:GET 返回 4 条规则;PUT 后 billing.json 保持规则形状;localzen(free)
请求不计入 unpriced,codearts 未列价模型计入(预期收紧)。
(cherry picked from commit 79bc55cfbe)
This commit is contained in:
@ -346,6 +346,21 @@ do
|
||||
if not res then plugin.load_error = tostring(err) end
|
||||
end
|
||||
|
||||
-- 插件 HTTP 分发把**整个请求表**交给 handler(method/path/body/headers…),
|
||||
-- body 是原始字符串;而直调导出(/call/...)拿到的就是参数表本身。这里统一
|
||||
-- 解出 JSON 载荷,避免"把请求信封当成规则写进 billing.json"(真实踩过:
|
||||
-- PUT 之后 billing.json 变成了整个请求的转储,规则全丢、价格表清空)。
|
||||
local function reqData(req)
|
||||
if type(req) ~= "table" then return {} end
|
||||
if type(req.json) == "table" then return req.json end
|
||||
if type(req.body) == "string" and req.body ~= "" then
|
||||
local ok, dec = pcall(json.decode, req.body)
|
||||
if ok and type(dec) == "table" then return dec end
|
||||
end
|
||||
if req.method == nil and req.path == nil then return req end
|
||||
return {}
|
||||
end
|
||||
|
||||
-- ---- 规则编辑器的 HTTP 面(挂在插件自己的 /api/plugins/http/billing/ 下)----
|
||||
-- 规则属于插件,写盘也在插件内完成;内核没有 billing 端点。
|
||||
function plugin.__http_rules_get(req)
|
||||
@ -359,7 +374,7 @@ function plugin.__http_rules_get(req)
|
||||
end
|
||||
|
||||
function plugin.__http_rules_put(req)
|
||||
local body = (req and (req.json or req))
|
||||
local body = reqData(req)
|
||||
if type(body) ~= "table" then
|
||||
return { status = 400, json = { error = "请求体必须是 JSON 对象" } }
|
||||
end
|
||||
@ -375,7 +390,7 @@ function plugin.__http_rules_put(req)
|
||||
end
|
||||
|
||||
function plugin.__http_rules_add(req)
|
||||
local body = (req and (req.json or req)) or {}
|
||||
local body = reqData(req) or {}
|
||||
local copy = json.decode(json.encode(plugin.rules or { active = "", profiles = {} }))
|
||||
local target = nil
|
||||
for _, p in ipairs(copy.profiles or {}) do
|
||||
@ -407,7 +422,7 @@ function plugin.__http_rules_add(req)
|
||||
end
|
||||
|
||||
function plugin.__http_rules_delete(req)
|
||||
local body = (req and (req.json or req)) or {}
|
||||
local body = reqData(req) or {}
|
||||
local copy = json.decode(json.encode(plugin.rules or { active = "", profiles = {} }))
|
||||
local target = nil
|
||||
for _, p in ipairs(copy.profiles or {}) do
|
||||
@ -448,14 +463,16 @@ function plugin.rules_put(args) return unwrap(plugin.__http_rules_put({ json = a
|
||||
function plugin.rules_add(args) return unwrap(plugin.__http_rules_add({ json = args or {} })) end
|
||||
function plugin.rules_delete(args) return unwrap(plugin.__http_rules_delete({ json = args or {} })) end
|
||||
|
||||
-- 每条路由的 path 必须唯一:内核的路由冲突仲裁按**路径**(不看 method)判重,
|
||||
-- 同一路径挂 4 个 method 会被当成 4 个插件抢同一个路径。所以按操作拆路径。
|
||||
plugin.http = {
|
||||
{ path = "billing/rules", method = "GET", handler = "__http_rules_get",
|
||||
roles = { "admin" }, description = "计费规则读取" },
|
||||
{ path = "billing/rules", method = "PUT", handler = "__http_rules_put",
|
||||
{ path = "billing/rules/replace", method = "PUT", handler = "__http_rules_put",
|
||||
roles = { "admin" }, description = "替换整份计费规则(插件自己写盘)" },
|
||||
{ path = "billing/rules", method = "POST", handler = "__http_rules_add",
|
||||
{ path = "billing/rules/add", method = "POST", handler = "__http_rules_add",
|
||||
roles = { "admin" }, description = "新增/替换一条计费规则" },
|
||||
{ path = "billing/rules", method = "DELETE", handler = "__http_rules_delete",
|
||||
{ path = "billing/rules/remove", method = "DELETE", handler = "__http_rules_delete",
|
||||
roles = { "admin" }, description = "删除一条计费规则" },
|
||||
}
|
||||
|
||||
@ -1524,8 +1541,9 @@ plugin.ui = {
|
||||
return { "&": "&", "<": "<", ">": ">", '"': """ }[c];
|
||||
});
|
||||
}
|
||||
var OP_PATH = { GET: "", PUT: "/replace", POST: "/add", DELETE: "/remove" };
|
||||
function call(method, body) {
|
||||
return fetch(API, {
|
||||
return fetch(API + (OP_PATH[method] || ""), {
|
||||
method: method,
|
||||
credentials: "same-origin",
|
||||
headers: body ? { "Content-Type": "application/json" } : undefined,
|
||||
|
||||
Reference in New Issue
Block a user