复写(Rewrite)
Rewrite 用于按条件修改 HTTP 请求或响应,也可以直接返回重定向、拒绝响应或 Mock 数据。
本文介绍 Loon 3.5.1 (978) 起支持的新语法。
生效范围
Rewrite 仅对 HTTP 和经过 MitM 解密的 HTTPS 请求生效,并在规则匹配前执行。
可视化生成
可以使用 Rewrite 配置生成器 组合条件和 Action,并直接复制结果。
快速开始
基本格式:
<phase> if <condition> then <action> [| <action> ...]
为请求添加 Header:
http-request if ${url} ~= /^https:\/\/api\.example\.com/ then request.header.set(name="X-Loon", value="true")
修改 JSON 响应:
http-response if ${url} ~= /^https:\/\/api\.example\.com\/profile$/ && ${response.status} == 200 then response.json.replace(path="data.vip", value=true)
多个 Action 使用 | 连接,并从左到右执行:
http-request if ${url} ~= /^https:\/\/api\.example\.com/ then request.header.set(name="X-Loon", value="true") | request.header.delete(name="Cookie")
每条 Rewrite 必须写在一行中。
执行阶段
| 阶段 | 时机 | 可用数据 |
|---|---|---|
http-request | 请求发出前 | URL、请求方法、请求 Header |
http-response | 收到响应 Header 后 | 请求数据、响应状态码、响应 Header |
请求和响应必须分开配置:
http-request if ${url} ~= /^https:\/\/example\.com/ then request.header.set(name="X-Test", value="request")
http-response if ${url} ~= /^https:\/\/example\.com/ then response.header.set(name="X-Test", value="response")
response.body.mock(...) 虽然生成响应,但会在请求阶段直接返回,因此只能用于 http-request。
条件
比较操作符
| 操作符 | 说明 |
|---|---|
== | 精确相等 |
~= | 正则匹配 |
http-request if ${request.method} == "POST" then request.header.set(name="X-Method", value="POST")
http-response if ${response.header['Content-Type']} ~= /^application\/json(?:;|$)/i then response.header.set(name="X-JSON", value="true")
~= 默认查找能够匹配的部分。需要匹配完整值时,请使用 ^ 和 $。
逻辑操作符
| 操作符 | 说明 |
|---|---|
&& | 并且 |
|| | 或者 |
() | 调整优先级 |
http-request if ${request.method} == "POST" && (${request.header['X-Region']} == "CN" || ${request.header['X-Region']} == "HK") then request.header.set(name="X-Matched", value="true")
优先级为:
比较操作符 > && > ||
同时使用 && 和 || 时,建议添加括号。
变量
所有动态值都使用 ${...}:
| 来源 | 示例 |
|---|---|
| 内置变量 | ${url} |
| 插件参数 | ${region} |
| 正则捕获 | ${item.1} |
内置变量
| 变量 | 类型 | 请求阶段 | 响应阶段 |
|---|---|---|---|
${url} | String | ✓ | ✓ |
${request.method} | String | ✓ | ✓ |
${request.header['name']} | String 或 null | ✓ | ✓ |
${response.status} | Number | — | ✓ |
${response.header['name']} | String 或 null | — | ✓ |
Header 名称不区分大小写:
${request.header['content-type']}
${request.header['Content-Type']}
请求阶段不能引用响应变量。当前版本也不支持在条件中读取请求或响应 Body。
插件参数
在插件 [Argument] 中声明参数:
[Argument]
enabled = switch,true,tag=启用
price = input,9.99,type=number,tag=价格
region = select,"CN","US","JP",tag=地区
在 Rewrite 中直接引用:
[Rewrite]
http-response if ${enabled} == true && ${request.header['X-Region']} == ${region} then response.json.replace(path="data.price", value=${price})
| 控件 | 支持类型 | 默认类型 |
|---|---|---|
input | String、Number | String |
select | String、Number | String |
switch | Boolean | Boolean |
input 和 select 需要返回数字时,使用 type=number:
price = input,9.99,type=number
level = select,1,2,3,type=number
参数只作为数据使用,不能生成新的条件或 Action,也不会进行二次变量展开。
正则捕获
使用 as <name> 保存匹配结果:
http-request if ${url} ~= /^https:\/\/api\.shop\.com\/item\/(\d+)/ as item then request.header.set(name="X-Item-ID", value="${item.1}")
| 变量 | 内容 |
|---|---|
${item.0} | 完整匹配内容 |
${item.1} | 第一个捕获组 |
${item.2} | 第二个捕获组 |
使用限制:
as只能用于~=。- 捕获名称在同一条 Rewrite 中必须唯一。
- 捕获名称不能与插件参数重名。
- 捕获下标不能超过正则中的捕获组数量。
- 捕获条件必须经过所有成功路径,不能放在
||的可选分支中。
有效:
http-request if (${request.method} == "GET" || ${request.method} == "POST") && ${url} ~= /item\/(\d+)/ as item then request.header.set(name="X-Item", value="${item.1}")
无效:
http-request if ${url} ~= /item\/(\d+)/ as item || ${request.header['X-Debug']} == "true" then request.header.set(name="X-Item", value="${item.1}")
如果可选捕获组未命中,引用它的 Action 会失败并跳过,后续 Action 继续执行。
值与字符串
字面量
| 类型 | 示例 |
|---|---|
| String | "hello world" |
| Number | 200、9.99 |
| Boolean | true、false |
| Null | null |
| Regex | /^https:\/\/example\.com/i |
固定字符串必须使用双引号。以下两个值类型不同:
value=9.99 # Number
value="9.99" # String
正则
格式:
/pattern/flags
支持的 Flag:
| Flag | 说明 |
|---|---|
i | 忽略大小写 |
m | 多行模式 |
s | . 匹配换行 |
正则字面量中不会展开 ${...}。需要由插件参数提供正则时,将变量放在 ~= 右侧:
http-request if ${url} ~= ${urlPattern} then request.header.set(name="X-Matched", value="true")
双引号字符串
双引号字符串支持变量:
request.header.set(name="X-Info", value="price=${price}, region=${region}")
支持以下转义:
| 写法 | 结果 |
|---|---|
\" | 双引号 |
\\ | 反斜杠 |
\n | 换行 |
\r | 回车 |
\t | Tab |
\${ | 字面量 ${ |