脚本运行限制与配置
本章讲脚本引擎的环境变量、限制与安全、脚本测试入口。API 参考见 脚本 API 参考,入门见 写第一个脚本变换。
脚本相关环境变量
| 变量 | 默认值 | 作用 |
|---|---|---|
SCRIPT_MAX_OPERATIONS | 2000 | 每次脚本执行的最大操作数 |
SCRIPT_MEMORY_LIMIT_MB | 64 | 解释器堆上限(MB) |
SCRIPT_LAZY_BODY | true | 是否对请求/响应体做懒投影;false 走旧整段物化分支 |
这三个控制操作数上限与内存;其他资源限制(字符串大小、数组元素、栈大小等)由沙箱硬编码,不可配置。改完环境变量需重启容器生效。完整环境变量见 环境变量配置参考。
资源限制
| 限制 | 值 | 可配置 |
|---|---|---|
| 最大操作数 | 2,000 | SCRIPT_MAX_OPERATIONS |
| 解释器堆上限 | 64 MB | SCRIPT_MEMORY_LIMIT_MB(运行时创建期约束,变更需重启) |
| body 懒投影 | 开启 | SCRIPT_LAZY_BODY(默认 true;false 走旧整段物化分支,回滚靠显式切回;变更需重启) |
| 最大字符串 | 10 MB | 固定 |
| 最大数组/对象元素 | 10,000 | 固定 |
| 正则缓存 | 256 条,5 分钟 TTL | 固定 |
| 栈大小 | 1024 帧 | 固定 |
ℹ️ body 视图语义:
SCRIPT_LAZY_BODY=true时,body是按需取件的懒投影视图,整份 body 不整段进 JS 堆,JS 堆占用只与脚本访问的字段挂钩。视图在Array.isArray/instanceof/typeof/Object.keys/ 解构 / 展开 /JSON.stringify/ 数组方法等标准判断下与真对象一致。已知边界:body.x === body.x为假(不缓存壳),依赖同路径引用相等的脚本须改用值比较。
沙箱限制
脚本可以做什么
- 读取和修改
body - 读取
context元数据 - 使用所有内置函数(json_path、str_、regex_、array_* 等)
- 定义辅助函数
- 使用标准 JavaScript(循环、条件、闭包、解构等)
脚本不能做什么
| 被禁止 | 原因 |
|---|---|
console.log / print | 防止信息泄露 |
| 文件 I/O | 无文件系统访问 |
网络 / fetch | 无网络访问 |
import / require | 不能加载外部代码 |
eval / Function | 不能动态执行代码 |
globalThis 修改 | 全局对象已冻结 |
错误处理
script_error_mode
| 模式 | 行为 | 适用场景 |
|---|---|---|
log-and-continue(默认) | 脚本报错时记录 warn 日志,请求以原始 body 继续 | 脚本失败不应阻断请求 |
log-and-reject | 脚本报错时拒绝请求,返回网关错误 | 脚本正确性至关重要(如安全脱敏) |
常见错误
| 错误 | 原因 | 解决 |
|---|---|---|
transform() must return a value | 某个 return 路径忘了返回 body | 每个 return 都必须返回 body |
TooManyOperations | 超过操作数上限(默认 2000) | 优化循环 |
TypeError | 访问 null/undefined 的属性 | 用 json_path() 或 in 运算符检查 |
ReferenceError | 使用未定义的变量或函数 | 检查拼写 |
提前返回时必须返回 body
function transform(body, context) {
// ✅ 正确
if (!body.messages) return body;
// ❌ 错误:return 无值 → 脚本静默失败
if (!body.messages) return;
body.messages[0].content = "modified";
return body;
}脚本测试
部署前先测试脚本。测试接口 POST /console/api/scripts/test 需要控制台认证——用环境变量 $CONSOLE_TOKEN 带上(它不是上游访问密钥,是控制台 API 凭证)。拿法二选一:
获取 CONSOLE_TOKEN
方式 1:配 CONSOLE_SECRET_KEY(推荐脚本 / CI 用)——设环境变量 CONSOLE_SECRET_KEY,控制台把它当 Bearer token 用,长期有效、不怕过期:
# 启动网关时注入
docker run -d -e CONSOLE_SECRET_KEY="my-secret-key-xxx" ... <镜像>
# 测试脚本时带上
export CONSOLE_TOKEN="my-secret-key-xxx"方式 2:用控制台账号登录拿 session token——不配 CONSOLE_SECRET_KEY 时走这条。POST /console/api/login 用账号密码登录,返回的 token 字段即 session token(默认 24 小时有效,调用会滑动续期):
export CONSOLE_TOKEN=$(curl -s http://localhost:7890/console/api/login \
-H "Content-Type: application/json" \
-d '{"username":"protoflux","password":"你的密码"}' | jq -r .token)CONSOLE_SECRET_KEY 与登录密码(CONSOLE_PASSWORD)相互独立,可只配其一。详见 控制台登录与角色。
curl -X POST http://localhost:7890/console/api/scripts/test \
-H "Authorization: Bearer $CONSOLE_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"script": "function transform(body, context) { body.model = context.upstreamModel; return body; }",
"body": {"model": "gpt-4o", "messages": []},
"context": {
"clientModel": "gpt-4o",
"upstreamModel": "gpt-4o-2024-05-13",
"upstreamName": "openai",
"sourceProtocol": "OpenAIChatCompletions",
"targetProtocol": "OpenAIChatCompletions",
"stream": false
}
}'响应:
{
"result_body": {"model": "gpt-4o-2024-05-13", "messages": []},
"execution_time_ms": 0.12
}POST /console/api/scripts/test。需要控制台 token 认证。
性能建议
性能与内存
脚本开销主要来自 JSON 序列化,耗时随 body 线性增长。after 槽大 body OOM 反模式、耗时参考与写法建议见 脚本性能与内存。
常见问题
Q:脚本在控制台界面哪里配? 上游详情页和模型详情页都有「请求脚本」「响应脚本」输入框。也可以直接通过 Console API 设置。
Q:脚本改了 body.model,为什么路由没变?body.model 只改请求体的字段,不改路由。要切换路由用 context.useModel("模型名")。
Q:流式请求的响应脚本生效吗? 暂不支持流式响应的脚本。请求脚本对流式请求有效,但响应脚本仅在非流式时生效。
Q:脚本报错了但请求正常通过? 默认的 log-and-continue 模式下,脚本报错不会阻断请求。查看 warn 日志了解报错原因。如需脚本必须成功,改用 log-and-reject。
Q:context.headers 里为什么没有 Authorization? 安全设计:authorization、cookie、x-api-key 等敏感 headers 在脚本可见之前已被移除,防止凭证泄露。
Q:怎么调大操作数上限?SCRIPT_MAX_OPERATIONS 可调。但建议先优化脚本——TooManyOperations 通常意味着循环复杂度过高。
下一步:脚本 API 参考 看完整内置函数表;写第一个脚本变换 看入门结构;环境变量配置参考 看全部环境变量;审计与安全配置 看其他安全设置。
