脚本 API 参考
Hodor 在内置 JavaScript 引擎中运行你的脚本。根据脚本类型,Hodor 会在恰当时机调用下方某个入口函数——只需实现需要的逻辑。如果不需要修改任何内容,删除未使用的入口函数即可避免不必要的调用。
可用的全局对象与类:
在脚本任意位置使用 console.log(...) 检查值——输出显示在脚本的日志视图中。
入口函数
引擎通过扫描 async function 声明识别脚本——每个入口函数的参数个数固定(onRequest/onResponse/onMock 为 3 个,onSessionCompleted 为 4 个,onSchedule 为 1 个)。箭头函数赋值(let onRequest = async (...) => {})不会被识别。参数名可以随意。
onRequest(context, url, request)
用于重写脚本与快速请求前置脚本。在 HTTP 请求发送到服务器前调用。返回(可能修改过的)request。
| 参数 | 类型 | 说明 |
|---|---|---|
context | RewriteContext | 上下文对象。 |
url | string | HTTP 请求的 URL。 |
request | Request | HTTP 请求对象。 |
// 修改请求体
async function onRequest(context, url, request) {
// 解析为文本
var text = request.body.parseText()
console.log(text)
request.body = "this is a replaced request text"
// 解析为 JSON
var json = request.body.parseJSON()
json["script_json"] = "JSONValue"
request.body = json
// 解析为 URLSearchParams
var urlencoded = request.body.parseURLSearchParams()
urlencoded.append("script", "parseURLSearchParams")
request.body = urlencoded
// 完成
return request;
}
// 重定向、修改 path / query / header
async function onRequest(context, url, request) {
console.log(url);
// 设置一个参数,可在 onResponse 中获取
context.parameters["custom"] = "custom parameter on request"
// 重定向
request.scheme = "http"
request.path = "/upload/json"
request.host = "192.168.3.30"
request.port = 6000
// 修改方法
request.method = "POST"
// query 操作
request.queries.append("name", "value1") // 添加 query
request.queries.set("name", "value2") // 替换或添加 query
request.queries.get("name") // 按 name 获取 query
request.queries.delete("name") // 按 name 删除 query
// header 操作
request.headers.delete("accept") // 按 name 删除 header
request.headers.append("hodor", "custom value") // 添加键值对
request.headers.forEach((value, name) => {
console.log(name + ":" + value)
});
// 完成
return request;
}
onResponse(context, url, response)
用于重写脚本与快速请求后置脚本。在 HTTP 响应发送到客户端前调用。返回(可能修改过的)response。
| 参数 | 类型 | 说明 |
|---|---|---|
context | RewriteContext | 上下文对象。 |
url | string | HTTP 响应的 URL。 |
response | Response | HTTP 响应对象。 |
// 响应体
async function onResponse(context, url, response) {
// 解析为文本
var text = response.body.parseText()
console.log(text)
response.body = "this is a replaced response text"
// 解析为 JSON
var json = response.body.parseJSON()
json["script_json"] = "JSONValue"
response.body = json
// 解析为 URLSearchParams
var urlencoded = response.body.parseURLSearchParams()
urlencoded.append("script", "parseURLSearchParams")
response.body = urlencoded
// 完成
return response;
}
// 修改状态码与 header
async function onResponse(context, url, response) {
// 获取 onRequest 中设置的参数
console.log(context.parameters["custom"]) // 输出 "custom parameter on request"
response.statusCode = 200 // 修改状态码
response.statusPhrase = "OK" // 修改状态短语
response.headers.delete("accept")
response.headers.append("hodor", "custom value")
response.headers.forEach((value, name) => {
console.log(name + ":" + value)
});
// 完成
return response
}
onSessionCompleted(context, url, request, response)
用于 HTTP 完成脚本。在 HTTP 响应返回后异步调用,不影响 App 与服务器之间的数据传输。适合做数据采集与转发。
| 参数 | 类型 | 说明 |
|---|---|---|
context | CompletedContext | 上下文对象。 |
url | string | HTTP 请求的 URL。 |
request | Request | HTTP 请求对象。 |
response | Response | HTTP 响应对象。 |
// 示例:将会话数据转发到自己的服务器
async function onSessionCompleted(context, url, request, response) {
try {
var reqText = request.body.parseText();
var rspText = response.body.parseText()
var params = {
"body": { // HTTPClient 的 POST body 数据
"url": url, // 请求 URL
"reqHeader": request.headers.encode(), // 请求 header
"reqText": reqText, // 请求体
"rspHeader": response.headers.encode(), // 响应 header
"rspText": rspText, // 响应体
},
"headers": { // HTTPClient header
"from": "onSessionCompleted"
},
}
const rsp = await HTTPClient.post("http://192.168.3.30:8000/upload", params)
let text = rsp.body.parseText()
console.log(text)
} catch(error) {
console.log(error)
}
}
onSchedule(context)
用于定时脚本。在计划触发时刻调用(支持 5 或 6 段 cron 表达式)。使用 abort() 停止定时循环。
| 参数 | 类型 | 说明 |
|---|---|---|
context | ScheduleContext | 上下文对象。 |
async function onSchedule(context) {
// 为下一次运行循环设置自定义参数
context.parameters["custom"] = "custom parameters for next runloop";
// 重复次数
console.log(`repeatedCount ${context.repeatedCount}`);
// 若 repeatedCount 为 2,停止定时
if (context.repeatedCount == 2) {
abort()
}
// 也可以使用 HTTPClient 发送请求
const rsp = await HTTPClient.get("https://www.apple.com")
let text = rsp.body.parseText()
console.log(text)
}
onMock(context, url, request)
用于 Mock 脚本。代替真实请求被调用——返回什么,客户端就收到什么。
| 参数 | 类型 | 说明 |
|---|---|---|
context | RewriteContext | 上下文对象。 |
url | string | HTTP 请求的 URL。 |
request | Request | HTTP 请求对象。 |
// 返回一个 Mock 的 JSON 响应
async function onMock(context, url, request) {
const response = new Response({
statusCode: 200,
statusPhrase: 'OK',
headers: {'Content-Type': 'application/json'},
textBody: JSON.stringify({code: 0, message: 'mocked by script', data: {time: Date.now()}}),
});
return response;
}
abort()
在通 道脚本(onRequest / onResponse / onSchedule)内调用 abort() 可立即停止脚本并中断当前执行——它会抛出 AbortError,由 Hodor 上报给你。
// ✅ 正确——abort() 被注入到脚本作用域
async function onRequest(context, url, request) {
if (url.includes("/tracking")) abort();
return request;
}
不要把入口函数写成 onRequest(context, url, request, aborter) 带 4 个参数。入口函数参数个数固定——第 4 个参数会导致入口无法被识别。
原生模块
所有带 $ 前缀的模块在运行时激活时注入。它们由原生实现、同步返回(除非特别说明),字符串输入按 UTF-8 处理。
$codec — 编码与解码
Base64 / Hex / URL 百分号编码,用于协议转换与数据传输。
| 方法 | 返回 |
|---|---|
$codec.base64Encode(str) | Base64 字符串。 |
$codec.base64Decode(str) | 解码结果;非法输入返回 ""(不抛异常)。 |
$codec.hexEncode(str) | 小写十六进制字符串。 |
$codec.hexDecode(str) | 解码结果;非法字符被跳过。 |
$codec.urlEncode(str) | 百分号编码字符串。 |
$codec.urlDecode(str) | 解码结果;非法序列原样返回。 |
$codec.base64Encode("Hello, World!"); // "SGVsbG8sIFdvcmxkIQ=="
$codec.base64Decode("SGVsbG8sIFdvcmxkIQ=="); // "Hello, World!"
$codec.hexEncode("ABC"); // "414243"
$codec.hexDecode("414243"); // "ABC"
$codec.urlEncode("hello world&foo=bar"); // "hello%20world%26foo%3Dbar"
$hash — 哈希
摘要计算,用于完整性校验、内容寻址与匿名化。返回小写十六进制。
| 方法 | 输出长度 |
|---|---|
$hash.md5(str) | 32 个十六进制字符 |
$hash.sha1(str) | 40 个十六进制字符 |
$hash.sha256(str) | 64 个十六进制字符 |
$hash.sha384(str) | 96 个十六进制字符 |
$hash.sha512(str) | 128 个十六进制字符 |
$hash.md5("hello"); // "5d41402abc4b2a76b9719d911017c592"
$hash.sha256("hello"); // "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
// 完整性校验
const checksum = $hash.sha256(JSON.stringify({user: "admin"}));
$hmac — 消息认证码
带密钥的哈希,用于 API 签名与防篡改。(data, key) 均按 UTF-8 编码;返回小写十六进制。
| 方法 | 算法 |
|---|---|
$hmac.md5(data, key) | HMAC-MD5 |
$hmac.sha1(data, key) | HMAC-SHA1 |
$hmac.sha256(data, key) | HMAC-SHA256 |
$hmac.sha384(data, key) | HMAC-SHA384 |
$hmac.sha512(data, key) | HMAC-SHA512 |
const signature = $hmac.sha256("important data", "my-secret-key");
const isValid = (signature === $hmac.sha256("important data", "my-secret-key")); // true
$crypto — 对称加密
AES-GCM 认证加密(推荐)与 DES(兼容旧场景)。
| 方法 | 返回 |
|---|---|
$crypto.encryptAES(plaintext, password, options?) | Base64 密文;失败返回 "Error: <原因>" 字符串。 |
$crypto.decryptAES(ciphertext, password, options?) | 明文;非法密文返回 "Error: Invalid ciphertext"。 |
$crypto.encryptDES(plaintext, key) | DES-ECB + PKCS7,key 截断到 8 字节 → Base64。 |
$crypto.decryptDES(ciphertext, key) | 明文;非 Base64 输入返回 ""。 |
options:{ keySize: 128 \| 192 \| 256 }(默认 256)。AES 密文格式为 base64(nonce[12] + ciphertext + tag[16])——请与 decryptAES 配对使用;与其他语言互操作时需自行拆解该格式。
const encrypted = $crypto.encryptAES("sensitive data", "my-password");
$crypto.decryptAES(encrypted, "my-password"); // "sensitive data"
// 128 位密钥
const e128 = $crypto.encryptAES("data", "pass", { keySize: 128 });
// 错误以字符串返回、不抛异常——检查前缀
const out = $crypto.decryptAES("not-base64!!", "p");
if (out.startsWith("Error:")) { /* 处理错误 */ }
$jwt — JSON Web Token
JWT 的创建、解析与签名校验(HMAC 家族),用于认证流程脚本。
| 方法 | 返回 |
|---|---|
$jwt.sign(payload, secret, algorithm?) | JWT 字符串;默认 HS256。 |
$jwt.decode(token) | {header, payload} 对象(不校验签名);非法 token 返回 null。 |
$jwt.verify(token, secret, algorithm?) | boolean——签名校验结果。 |
algorithm:"HS256" | "HS384" | "HS512"。
// 签名
const payload = JSON.stringify({ sub: "user123", exp: Math.floor(Date.now() / 1000) + 3600 });
const token = $jwt.sign(payload, "my-secret", "HS256");
// 解码——直接返回对象,无需 JSON.parse
const decoded = $jwt.decode(token);
decoded.header.alg; // "HS256"
decoded.payload.sub; // "user123"
// 校验
$jwt.verify(token, "my-secret", "HS256"); // true
$jwt.verify(token, "wrong-secret", "HS256"); // false
// 过期检查
const exp = $jwt.decode(token).payload.exp;
const expired = exp * 1000 < Date.now();
$format — 数据格式化
JSON/XML 的美化与压缩,用于日志输出与调试。JSON 输出中键按字母序排列。
| 方法 | 返回 |
|---|---|
$format.json(str, indent?) | 美化后的 JSON;indent 限制在 1–8(默认 2);非法输入返回 "Error: Invalid JSON"。 |
$format.minify(str) | 压缩后的 JSON(键排序、去除空白);非法输入返回 "Error: Invalid JSON"。 |
$format.xml(str) | 简单缩进的 XML。 |
$format.json('{"b":1,"a":2}');
// {
// "a": 2,
// "b": 1
// }
$format.json('{"a":2}', 4); // 4 空格缩进
$format.minify('{ "a": 2 }'); // '{"a":2}'
$format.xml('<root><child>t</child></root>');
// <root>
// <child>t</child>
// </root>
$fs — 文件系统
脚本内的轻量文件读写(配置、缓存、导出)。路径支持 ~ 展开;write 会自动创建缺失的父目录。
| 方法 | 返回 |
|---|---|
$fs.read(path) | UTF-8 内容;失败返回 "Error: Cannot read file at <path>"。 |
$fs.readBinary(path) | 字节(Base64);失败返回 ""。 |
$fs.write(path, content) | boolean——是否成功。 |
$fs.exists(path) | boolean。 |
$fs.delete(path) | boolean;文件不存在返回 false。 |
$fs.list(path) | 目录条目 string[];失败返回 []。 |
$fs.info(path) | JSON 字符串 {size, modified, isDirectory, path};路径不存在返回 undefined。 |
const file = $env.tmpDir() + "/hodor-test.txt";
$fs.write(file, "Hello from Hodor!");
$fs.read(file); // "Hello from Hodor!"
$fs.exists(file); // true
$fs.list($env.tmpDir()); // ["hodor-test.txt", ...]
const info = JSON.parse($fs.info(file));
info.size; // 字节数
info.isDirectory; // false
$fs.delete(file); // true
各方法的失败形态不同:read 返回 "Error: ..." 字符串、readBinary 返回 ""、list 返回 []、info 返回 undefined——请分别处理。
$env — 环境变量
进程环境变量与系统路径。注意:$env 是进程环境(各次执行间共享,随进程存续)。如需面向用户的持久变量,请使用 sdk.setEnvVar 或 SharedPreferences。
| 方法 | 返回 |
|---|---|
$env.get(key) | 值;不存在的 key 返回 ""。 |
$env.set(key, value) | boolean——setenv 结果。 |
$env.all() | 所有环境变量的 JSON 字符串。 |
$env.cwd() | 当前工作目录。 |
$env.tmpDir() | 临时目录。 |
$env.homeDir() | 用户主目录。 |
$env.set("APP_VERSION", "1.0.0");
$env.get("APP_VERSION"); // "1.0.0"
const all = JSON.parse($env.all());
$uuid — UUID
生成与校验 UUID(请求 ID、幂等键)。
| 方法 | 返回 |
|---|---|
$uuid.v4() | 标准 v4 UUID(大写、带连字符),如 "550e8400-E29B-41D4-A716-446655440000"。 |
$uuid.compact() | 无连字符的小写形式。 |
$uuid.validate(str) | 字符串是否为合法 UUID。 |
const id = $uuid.v4();
$uuid.compact(); // "550e8400e29b41d4a716446655440000"
$uuid.validate($uuid.v4()); // true
$uuid.validate("not-uuid"); // false
validate 只接受带连字符的格式——validate($uuid.compact()) 返回 false。校验紧凑字符串前需先补回连字符。
$log — 结构化日志
带时间戳、分级的日志行,经引擎 console 系统输出(汇总到脚本的日志视图)。
| 方法 | 返回 |
|---|---|
$log.log(level, message, tag?) | 格式化日志行(同时打印)。 |
$log.debug / info / warn / error(message) | 各分级便捷方法,仅输出。 |
日志行格式:[yyyy-MM-dd'T'HH:mm:ss.SSSZ] [LEVEL] [tag] message(未提供 tag 时省略 [tag] 段)。
$log.info("Server started on port 8080");
// [2025-07-24T01:11:45.548+0800] [INFO] Server started on port 8080
$log.log("info", "Request processed", "API");
// [2025-07-24T01:11:45.548+0800] [INFO] [API] Request processed
Web API
fetch
从脚本发送真实 HTTP 请求——Postman 风格工作流的主要通道。
fetch(url: string, options?: object) → Promise<response>
options:
| 字段 | 类型 | 默认 | 说明 |
|---|---|---|---|
method | string | "GET" | 大小写不敏感;未知值回退为 GET。 |
timeoutInterval | number | 30 | 秒。 |
headers | [[k, v]] 或 [{k: v}] | [] | 两种形态均可。 |
textBody | string | — | 请求体文本。 |
encoding | string | — | "hex" 表示 textBody 为十六进制字符串。 |
resolve 的值是普通对象:statusCode(number)、headers(单键对象数组,重复键保留)、textBody()——返回 {text, encoding} 的函数,自动检测字符集(无法解码时回退 {text: <hex>, encoding: "hex"})。reject 的值是错误消息字符串。
// GET
const rsp = await fetch("https://httpbin.org/get");
if (rsp.statusCode === 200) {
const body = rsp.textBody(); // {text: "...", encoding: "utf-8"}
const json = JSON.parse(body.text);
}
// POST JSON
const rsp2 = await fetch("https://httpbin.org/post", {
method: "POST",
headers: [["Content-Type", "application/json"]],
textBody: JSON.stringify({a: 1}),
timeoutInterval: 10,
});
HTTPClient
HTTPClient 类从任意脚本发送 HTTP 请求(基于 fetch 实现)。所有方法均为 async,返回带 statusCode、headers、textBody() 的响应对象。
| 方法 | 说明 |
|---|---|
HTTPClient.get(url, params?) | 发送 GET 请求。 |
HTTPClient.post(url, params?) | 发送 POST 请求。 |
HTTPClient.put(url, params?) | 发送 PUT 请求。 |
HTTPClient.update(url, params?) | 发送 UPDATE 请求。 |
HTTPClient.delete(url, params?) | 发送 DELETE 请求。 |
HTTPClient.request(url, method, params?) | 发送自定义方法的请求。 |
params 为可选对象:
headers:请求 header 对象,如{"key1": "value1"}body:请求体——字符串、JSON 对象(自动序列化)或 URLSearchParamstimeoutInterval:超时秒数(默认 60)
try {
var params = {
"headers": {"key1": "value1"},
"body": {"a": "a1", "b": "b1"},
};
const response = await HTTPClient.post("https://dummyjson.com/products/1", params);
console.log(response.textBody().text);
} catch(error) {
console.log(error);
}
定时器
setTimeout / setInterval / clearTimeout / clearInterval 与浏览器中行为一致。回调派发在引擎的串行队列上,与宿主线程无关,触发可靠。
| 函数 | 返回 |
|---|---|
setTimeout(callback, ms) | 定时器 id(string),触发一次。 |
setInterval(callback, ms) | 定时器 id,重复触发。 |
clearTimeout(id) / clearInterval(id) | 取消(幂等,未知 id 被忽略)。 |
await new Promise(resolve => setTimeout(resolve, 500)); // 等待 0.5s
const timer = setInterval(() => console.log("tick"), 1000);
setTimeout(() => clearInterval(timer), 3500);
全局函数
| 名称 | 签名 | 说明 |
|---|---|---|
btoa(str) | (string) → string | Base64 编码——UTF-8 对称语义(与浏览器不同,非 Latin1 字符串也可用)。 |
atob(str) | (string) → string | Base64 解码;非法输入返回 ""。 |
performance.now() | () → number | 自 epoch 起的毫秒数(非页面加载时间)。 |
sleep(ms) | (number) → Promise | ms 后 resolve;使用 await sleep(1000)。 |
require(id) | (string) → any | 按 CommonJS 语义(module.exports)加载脚本库;引用键为 @libs/<键>,解析顺序:脚本库 identifier → 脚本库 name(唯一匹配)→ 内置库;未命中抛错。 |
TextEncoder | new TextEncoder().encode(str) | UTF-8 编码为 Uint8Array(encoding 恒为 "utf-8")。 |
crypto.getRandomValues(n) | (Array) → number[] | 填充 n 个随机 UInt32 值。 |
crypto.randomUUID() | () → string | 随机 UUID(大写、带连字符)。 |
btoa("Hello"); // "SGVsbG8="
atob("SGVsbG8="); // "Hello"
btoa("中文"); // 可用——按 UTF-8 字节编码
performance.now(); // 1760000000000.123
await sleep(100);
const { encode } = require("@libs/base64"); // 内置库
const { sign } = require("@libs/sign-lib"); // 你的脚本库
new TextEncoder().encode("hi"); // Uint8Array [104, 105]
脚本库在脚本模块管理中维护。require 引用键固定为 @libs/<键>:先按 identifier 精确匹配你的脚本库(重命名不断链),再按 name 唯一匹配,最后解析内置库 @libs/base64 / @libs/hex。库通过 module.exports 导出、可以再 require 其他库,未命中抛错(前置失败中止发送,后置失败保留原始响应)。完整用法见快速请求 scripting 的 require 引用脚本库。
console
console.log / info / warn / error 将值打印到脚本的日志视图。多参数会被序列化,可直接输出对象与数组:
console.log("headers", {Accept: "application/json"}, [1, 2, 3]);
$log 提供结构化分级输出(见 $log)——两个通道在 Hodor 的脚本日志视图中均可见。
HTTP 类
Request
Request 类是传给 onRequest / onSessionCompleted 的封装 HTTP 请求。
| 成员 | 类型 | 说明 |
|---|---|---|
scheme | string(get / set) | 请求协议,如 https。 |
host | string(get / set) | 请求主机。 |
port | number(get / set) | 请求端口。 |
path | string(get / set) | 请求路径。 |
method | string(get / set) | HTTP 方法,如 GET。 |
queries | URLSearchParams(get) | 请求 query 参数。 |
headers | Headers(get) | 请求 header。 |
body | Body(get)/ string | Map | Array | URLSearchParams(set) | 请求体。 |
header 必须通过 .set() / .append() 修改——索引赋值(如 headers["X-Key"] = v)会被忽略。
也可以自行构造请求:
const request = new Request({
scheme: 'https',
host: 'example.com',
port: 8080,
path: '/api',
method: 'GET',
queries: 'param1=value1¶m2=value2',
headers: [
['Content-Type', 'application/json'],
['Authorization', 'Bearer token']
],
textBody: '{"key": "value"}'
});
console.log(request.encode());
Response
Response 类表示传给 onResponse / onSessionCompleted 的 HTTP 响应。
| 成员 | 类型 | 说明 |
|---|---|---|
statusCode | number(get / set) | 响应状态码。 |
statusPhrase | string(get / set) | 响应状态短语,如 OK。 |
headers | Headers(get) | 响应 header。 |
body | Body(get)/ string | Map | Array | URLSearchParams(set) | 响应体。 |
const response = new Response({
statusCode: 404,
statusPhrase: 'Not Found',
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
},
textBody: '{"error": "Resource not found"}'
});
console.log(response.encode());
Body
Body 类表示 HTTP 请求或响应的 body。给 request.body / response.body 赋新值会整体替换 body。
| 方法 | 返回 | 说明 |
|---|---|---|
parseText() | string | null | 将 body 解析为文本。 |
parseJSON() | object | null | 将 body 解析为 JSON。 |
parseURLSearchParams() | URLSearchParams | null | 将 body 解析为 URL 编码参数。 |
const bodyInstance = new Body('{"user": "alice"}');
const json = bodyInstance.parseJSON();
if (json) {
console.log('User:' + json.user);
} else {
console.error('Failed to parse JSON');
}
Headers
Headers 类表示 HTTP header。
| 方法 | 返回 | 说明 |
|---|---|---|
append(name, value) | void | 向指定 header 追加值。 |
set(name, value) | void | 设置(替换)指定 header 的值。 |
get(name) | string | null | 获取指定 header 的值。 |
has(name) | boolean | 检查指定 header 是否存在。 |
delete(name) | void | 删除指定 header。 |
forEach(callback, thisArg?) | void | 对每个 header 调用函数。 |
entries() / keys() / values() | Iterator | 遍历条目 / 键 / 值。 |
encode() | Array | 将 header 编码为 可序列化格式。 |
const headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.set('Content-Length', '1024');
console.log(headers.get('Content-Type')); // 'application/json'
console.log(headers.has('Authorization')); // false
headers.forEach((value, name) => {
console.log(name + ' ' + value);
});
URLSearchParams
URLSearchParams 类表示 URL query(或 urlencoded body)参数。
| 方法 | 返回 | 说明 |
|---|---|---|
append(name, value) | void | 向指定参数追加值。 |
set(name, value) | void | 设置(替换)指定参数的值。 |
get(name) | string | null | 获取指定参数的值。 |
has(name) | boolean | 检查指定参数是否存在。 |
delete(name) | void | 删除指定参数。 |
forEach(callback, thisArg?) | void | 对每个参数调用函数。 |
entries() / keys() / values() | Iterator | 遍历条目 / 键 / 值。 |
sort() | void | 排序参数。 |
toString() | string | 序列化为 urlencoded 字符串。 |
const params = new URLSearchParams({ key1: 'value1', key2: 'value2' });
console.log(params.get('key1')); // 'value1'
console.log(params.get('key3')); // null
params.forEach((value, key) => console.log(key + ' ' + value));
SharedPreferences
SharedPreferences 类提供本地持久化键值存储,跨脚本运行与 App 重启保留(底层为系统 user defaults)。
| 方法 | 返回 | 说明 |
|---|---|---|
SharedPreferences.write(key, value) | void | 写入值(string / number / boolean / object / array)。写 null 删除该 key。 |
SharedPreferences.read(key) | any | 读取 key 关联的值,不存在返回 null。 |
SharedPreferences.write("test_key", "test_value");
const value = SharedPreferences.read("test_key");
console.log(value);
SharedPreferences.write("cfg", {a: 1}); // 对象直接存储
SharedPreferences.write("cfg", null); // 删除 "cfg"
sdk——快速请求脚本
sdk(别名 pm)仅在快速请求前置/后置脚本注入。它桥接 App 的变量存储(环境、全局与运行时变量)并收集断言,API 形态与 Postman 类似。
| 成员 | 说明 |
|---|---|
sdk.env.get(key) | 读取 App 中定义的环境变量。 |
sdk.env.set(key, value) | 设置环境变量(同 sdk.setEnvVar)。 |
sdk.setEnvVar(key, value) | 写入环境变量——收集后回写到 App。 |
sdk.setVar(key, value) | 写入运行时(局部)变量。 |
sdk.setGlobalVar(key, value) | 写入全局变量。 |
sdk.getVar(key) | 读取运行时变量。 |
sdk.test(name, fn) | 运行命名断言块;失败被收集并在 App 中上报。 |
sdk.expect(value) | 断言原语:toBe、toEqual、toBeTruthy。 |
sdk.jsonPath(object, path) | 点路径查找,如 "$.data.list[0].id"。 |
sdk.utils.uuid() | 同 crypto.randomUUID()。 |
sdk.utils.base64Encode(s) / base64Decode(s) | 同 btoa / atob。 |
sdk.utils.md5(s) | 同 $hash.md5。 |
// 快速请求前置脚本:给请求签名
async function onRequest(context, url, request) {
// 读取 App 环境中定义的变量
const secret = sdk.env.get("secret") || "test-key";
sdk.expect(secret).toBeTruthy();
const ts = String(Date.now());
const bodyText = request.body && request.body.text ? request.body.text : '';
const sig = $hmac.sha256(ts + bodyText, secret);
// header 必须通过 .set / .append 设置
request.headers.set("X-Signature", sig);
request.headers.set("X-Timestamp", ts);
// 将变量回写到 App
sdk.setEnvVar("lastTs", ts);
sdk.test("signature is 64 hex", () => {
sdk.expect(sig.length).toBe(64);
});
console.log("signed request for", url);
return request;
}
断言结果仅在前置脚本中上报。后置脚本中断言会执行,但结果不会被收集。
上下文
RewriteContext
传给重写脚本 (onRequest / onResponse)的上下文对象。
| 成员 | 类型 | 说明 |
|---|---|---|
isEnableOnRequest | boolean(get) | onRequest 入口是否启用。 |
isEnableOnResponse | boolean(get) | onResponse 入口是否启用。 |
parameters | object(get / set) | onRequest 与 onResponse 之间共享的参数字典。 |
scriptName | string(get) | 脚本名称。 |
CompletedContext
传给 HTTP 完成脚本的上下文对象。
| 成员 | 类型 | 说明 |
|---|---|---|
session | object(get) | 与完成脚本关联的会话对象。 |
scriptName | string(get) | 完成脚本名称。 |
ScheduleContext
传给定时脚本的上下文对象。
| 成员 | 类型 | 说明 |
|---|---|---|
parameters | object(get / set) | 设置后传给下一次运行循环的参数。 |
cron | string(get) | 定时的 cron 表达式。 |
repeatedCount | number(get) | 脚本已重复执行的次数。 |
scriptName | string(get) | 定时脚本名称。 |
行为说明
- 未捕获异常会导致脚本失败。 错误(包括
abort()抛出的AbortError)会传播给 Hodor,执行被上报为失败——错误发生前的部分重写会被丢弃,风险代码块请用try / catch保护。 - 超时看门狗。 每次脚本运行有时间预算;永不结束的脚本(如死循环或挂起的
await)会被强制中断并上报为超时。 - 错误作为返回值。 部分 API 永不抛异常:
$codec.base64Decode返回""、$crypto返回"Error: ..."字符串、$fs.read返回"Error: ..."字符串、$fs.info返回undefined。请检查返回值而非依赖try / catch。 console.log与$log。 两者在脚本日志视图中均可见;$log额外带时间戳与分级。- 脚本运行时持久化。
sdk.setVar写入的变量与$fs写入的文件对同一脚本的后续执行仍可用;SharedPreferences跨 App 重启保留。