@wuxuejun
2017-12-25T08:01:01.000000Z
字数 8671
阅读 2012
又拍云 CDN 边缘网络中的智能可扩展应用程序规则可以帮助您简化内容分发业务逻辑,并提升终端用户访问体验。该规则可以快速部署且配置简单,可极大降低业务实现成本。
网站及Web 应用开发者或者安全工程师可以创建边缘规则集来提升网站安全及分发性能。例如,这些场景可能包括:
您可以根据实际使用场景,合理选择功能项。
使用方式
EdgeRules 根据不同用户划分了两种不同的使用方式,一种是通用模式,一种是编程模式。
通用模式
适用于没有开发基础的用户,使用方便快捷,用户体验会更好一些;
编程模式
适用于开发者,对 EdgeRules 语法规则有很深了解的用户,相对通用模式来说,编程模式会更灵活,功能会更强大一些。
条件判断
默认情况下,EdgeRules 是根据服务维度生效的,您也可以添加条件判断,当条件满足某些特定要求时,才会触发后面的功能选项。例如:
当请求 HOST 为 test.example.com 时,添加 HTTP 响应头 CDN 为 UPYUN。
这些条件过滤器包括:
为了配合条件判断使用,支持的运算符包括:
如希望通过编程模式来使用变量,更多了解参考。
功能选择
根据使用场景,我们针对通用模式配备了 7 大功能,具体功能列表包括:
下文将对 7 大功能进行实例介绍,方便理解。
1)添加 HTTP 头部
基于业务场景添加 HTTP 头部,包括 HTTP 请求头和 HTTP 响应头,例如:添加跨域配置。具体规则描述如下:
if($_HOST == www.example.com){
ADD_Response_Header Access-Control-Allow-Origin "*"
}
2)删除 HTTP 头部
基于业务场景删除 HTTP 头部,包括 HTTP 请求头和 HTTP 响应头,例如:强制删除 Accept-Encoding,资源内容不进行 Gzip 压缩 。规则描述如下:
if($_HOST == www.example.com){
Delete_Request_Header Accept-Encoding
}
3)边缘重定向
可以根据特定地区的用户响应不同页面内容,也即智能内容适配。这里以国家代码为例,当终端用户为英国地区的用户,则将请求 302 重定向到指定页面。具体规则如下:
if($_GEOIP_COUNTRY_CODE == GB ){
Edge_Redirect https://english.example.com/index.html 302
}
4)URL 改写
配合网站将动态 URL 转换为语义 URL,改善搜索引擎索引机制,提高网站 SEO 排名。将原始请求 http://www.example.com/pay/25/8/... 进行 URL 改写。 具体 规则描述如下:
if($_HOST == www.example.com){
String Extract ^pay/([0-9]+)/([0-9]+)/(.*?).html$
URL Rewrite /pay.php?productid=$1&categoryid=$2
}
5)请求限速
在不影响终端用户体验的情况下,将请求速度控制在合理范围之内,节省 CDN 带宽。示例规则如下:开始 20MB 不限速,后面限制到 800KB/s。
if($_HOST == www.example.com){
Limit_Rate after 20MB,rate 800KB/s
}
6)访问控制
灵活针对请求内容进行访问控制,可以响应 403/404 状态码。这里针对 User-Agent 进行过滤,比如:来自搜狗等爬虫的请求直接响应 403 状态码。具体规则如下:
if($_HEADER_user_agent ~ 'shanks/0.8.3|BLEXBot/1.0|Sogou web spider/4.0|YisouSpider'){
Access_Control 403
}
7)自定义错误页面
自定义源站错误页面,而非 CDN 默认指定的错误页面。这里以 404 错误页面为例,当源站响应 404 状态该码时,则 302 重定向到指定 404 页面。具体规则如下:
if($_HOST == www.example.com){
ErrorPage_404 http://www.upyun.com/404.html 302
}
优先级
又拍云 EdgeRules 是按照先后顺序执行的。优先级在前面的规则将会优先执行,您需要根据业务需求来合理调整规则的优先级。
break
该开关默认为关闭状态。开启状态下,如果此条规则命中则终止匹配剩下的规则,也即会跳出整个规则集,请结合业务需求合理开启和关闭。
状态
1)启用
启用状态下,规则会在几秒钟内下发部署到全网 CDN 节点,及时生效。请确保业务测试成功之后,再调整为启用状态。
2)关闭
关闭状态下,规则不会在全网 CDN 节点进行部署。请根据业务情况,有选择性的关闭规则。
3)测试
规则默认为测试状态,平台会自动获取本地 IP 地址,也即规则只会对该客户端 IP 生效,您也可以换成其他 IP 地址进行测试。当且仅当测试满足业务要求之后,你才可以将规则调整为启用状态。
当您希望通过编程模式来自行编写边缘规则时,你需要对又拍云边缘规则的语法规则进行详细了解,方可自行编写规则。本文将围绕函数、变量、字符串常量、break 进行详细介绍。
函数调用以 $
开头,后跟一组大写字母,字母之间可以包含下划线 _
,函数需要的参数放在()
中,以 ,
分隔。如果没有特别说明,边缘规则 中的函数参数个数不能少于要求的参数个数,否则视为语法错误,然后终止规则执行过程,多余的参数会被求值,但不影响调用。函数调用是有上下文的,譬如 $WHEN
这个函数,参数是 bool
类 型,参数中有不成立的条件 false
时,会终止本次规则执行过程。支持的函数有:
条件选择和判断
函数 | 含义 |
---|---|
$WHEN(E1, E2, ...) |
所有条件都成立时才会执行规则,并返回空字符串 |
$NOT(E) |
E 不成立时返回 true , 否则返回 false |
$ALL(E1, E2, ...) |
所有条件都成立时返回 true ,否则返回 false ,参数个数不限 |
$ANY(E1, E2, ...) |
其中一个条件成立时返回 true ,否则返回 false ,参数个数不限 |
$OR(E1, E2, ...) |
值为第一个为真的表达式 |
$SELECT(E1, E2, E3) |
E1 为真时值为 E2 ,否则为 E3 |
$PCALL(E) |
保护模式下解析 E ,失败时返回空字符串 |
字符匹配和捕获
函数 | 含义 |
---|---|
$MATCH(E1, E2) |
PCRE 匹配,E2 为要匹配的 pattern,返回 true 或者 false |
$CAPTURE(E1, E2, E3) |
按 E2 pattern 对 E1 进行捕获,E3 表示是否忽略大小写,捕获后生成 $n.m 形式的变量,n 为当前 CAPTURE 出现的次序,m 表示匹配分组;E2 为空时,表示对 E1 进行捕获,此时 E1 对应 $n.0 |
请求/响应修改
函数 | 含义 |
---|---|
$ADD_REQ_HEADER(E1, E2) |
添加请求头 E1 为 E2 |
$DEL_REQ_HEADER(E) |
删除请求头 E |
$ADD_RSP_HEADER(E1, E2) |
添加响应头 E1 为 E2 |
$DEL_RSP_HEADER(E) |
删除响应头 E |
$DEL_ARG(E) |
删除请求参数项 E |
$SET_METHOD(E) |
修改当前 HTTP 请求方法为 E ,E 可选值有:GET , HEAD , PUT , POST , DELETE , OPTIONS , PATCH ; 注 1 |
$SET_BODY(E) |
修改当前 HTTP 请求体的内容为 E ,仅在 PUT 或 POST 请求下有效 |
$REDIRECT(E1, E2) |
重定向地址到 E1 ,状态码为 E2(301, 302) |
$EXIT(E1, E2) |
以状态码 E1 退出,响应体为 E2 |
注: 删除响应头函数不能删除 CDN 自带的一些字段,比如 via、age、server、connection、x-cache、x-request-id、x-source、content-length、transfer-encoding等字段是有保护的。
数值计算
函数 | 含义 |
---|---|
$ADD(E1, E2) |
数字相加,返回 E1 + E2 结果数值 |
$MOD(E1, E2) |
数字取余,返回 E1 % E2 结果数值,其中 E2 不能为 0 |
$MSUB(E1, E2) |
数字相减,返回 E1 - E2 结果数值 |
$MULTIPLY(E1, E2) |
数字相乘,返回 E1 * E2 结果数值 |
$DIVIDE(E1, E2) |
数字相除,返回 E1 / E2 结果数值,其中 E2 不能为 0 |
$BYTE(E) |
返回字符 E 的 ASCII 编码值 |
$FLOOR(E) |
返回小于或等于数字 E 的最大整数 |
$CEIL(E) |
返回大于或等于数字 E 的最小整数 |
$GT(E1, E2) |
数字比较,是否大于,返回 true 或者 false |
$GE(E1, E2) |
数字比较,是否大于等于,返回 true 或者 false |
字符串操作
函数 | 含义 |
---|---|
$SUB(E1, from, to) |
字符串截取,从 from 到 to |
$EQ(E1, E2) |
字符串是否相等,返回 true 或者 false |
$UPPER(E) |
将 E 转换为大写 |
$LOWER(E) |
将 E 转换为小写 |
$LEN(E) |
返回字符串 E 的长度 |
通用功能类函数
函数 | 含义 |
---|---|
$ENCODE_BASE64(E) |
将字符串 E 按 base64 编码压缩 |
$DECODE_BASE64(E) |
将字符串 E 按 base64 编码解压 |
$MD5(E) |
计算 E 的 md5 值 |
$RANDI(E1, E2) |
返回大于 E1 并小于 E2 的随机数值 |
$UNIXT(y, m, d, h, min, sec) |
指定年,月,日,小时,分钟,秒,返回相应的 UNIX TIME |
$INT(E1, E2, E3) |
进制转换,将 E2 进制的数字(字符串形式) E1 转换成 E3 进制并返回,E2 , E3 可选,E2 默认为 10 |
限速相关
函数 | 含义 |
---|---|
$LIMIT_RATE_AFTER(E1, E2) |
限速策略设置,发送 E1 大小单位为 E2 字节数据后,进行限速,E2 可选值有:k (KB),m (MB) |
$LIMIT_RATE(E1, E2) |
限速策略设置,按 E1 大小每秒进行限速,单位为 E2 ,E2 可选值有:k (KB),m (MB) |
注 1:若当前请求带有请求体的情况下,$SET_METHOD(E)
不允许设置为除 PUT
和 POST
以外的方法。
其中 E[n]
代表合法的表达式,也就是说函数可以相互嵌套,例如规则可以为:
/$SUB($DECODE_BASE64($_HEADER_foo), $_GET_from, $_GET_to)/
;布尔函数包括 WHEN
都是短路的,譬如
, ALL, ANY$WHEN($ALL(), $EXIT(403))
不会返回 403
,因为
$ALL()
的值为 false
使用 ''
能对变量进行转义,使其不被解释,例如以下规则:
/foo/'$_HOST'
会被转换为:
/foo/$_HOST
对于含有请求参数的规则,原先的请求参数会附加到后面,如果不希望这样,可以放置一个
'?' 在规则的最后面,例如这样:
/foo?bar=$1?
特别地,如果重写后的 URL 没有参数,那么此时需要在最后加两个 ?
,例如这样:
/foo??
变量以 $_
开头,这些变量都是对此次请求上下文中一些参数的映射,譬如 $_HOST
对应此次请求头中的 Host
字段,$_GET_foo
对应此次请求 URL 参数 foo 的值,等等。若将变量内插到重写后的 URL 中,譬如 URL 改写 /$_GET_foo/bar
,如果请求参数中没有 foo
则视为此次改写 失败;
若将变量放在函数中,则由该函数确定返回的值,例如 $NOT($_GET_foo)
,如果参数中包含 foo
,则返回 false
,否则返回true
。目前支持的变量有:
变量 | 含义 |
---|---|
$_IP |
客户端 IP |
$_HOST |
请求头中的 Host 字段 |
$_HOST_n |
$_HOST_n 指 Host 中的第 n 个子域,例如对于 foo.bar.baz.com:$_HOST_1 = foo,$_HOST_2 = bar,$_HOST_3 = baz |
$_GET_name |
使用 Query String 中的变量(无需 urldecode) |
$_POST_name |
使用 POST 表单中的变量(只支持 www form ) |
$_HEADER_name |
使用 Header 中的值,注意 name 全为小写 |
$_COOKIE_name |
使用 Cookie 中的字段值 |
$_RANDOM |
随机字符串,字符集为 [a-zA-Z0-9] ,默认 8 位 |
$_RANDOM_n |
n 位随机字符串,其中 1 <= n <= 32 |
$_URI |
请求的 URI,不包含参数 |
$_QUERY |
Query String,不带前缀 '?' |
$_METHOD |
GET/POST/PUT/POST/DELETE/OPTIONS/PATCH |
$_SCHEME |
http/https,注意此处全为小写 |
$_TIME |
获取当前服务器时间,格式为 UNIX TIME |
$_BODY |
获取当前请求的 BODY(请求体)内容,大小限制为 16KB |
$_GEOIP_COUNTRY_CODE |
国家代码,可参照维基百科: https://en.wikipedia.org/wiki/ISO_3166-2 |
字符串常量有两种形式,第一种就是普通的字符串例如/foo/bar
,但是如果字符串中包含了一些特殊字符,例如空白字符将被省略,例如 $(),'
这些字符有特殊的用途,不能被直接使用,要使用这些特殊的字符,要加 \
前缀对其转义,例如 /foo/bar\,
;第二种是加单引号的字符串 ''
,单引号中的字符只有 \
是特殊转义字符前缀,其他的都视为普通字符,例如这样一条改写规则 /foo/'$\\,\''
,改写过后对应 /foo/$\,'
。
除了能勾选 break 选项
指定是否 break
,也可以直接在边缘规则最后加上 $$
表示 break
。
在这个章节,我们会介绍如何添加和编辑边缘规则集,主要大纲包括:
登陆 CDN 控制台,依次进入:服务管理 > 功能配置 > 边缘规则 > EdgeRules,即可进入边缘规则管理界面。如下图所示:
截图:后续添加
在规则管理界面,针对每一条规则,控制台提供了如下字段信息:
字段 | 描述 |
---|---|
优先级 | 指定规则执行的先后顺序 |
规则名称 | 该条规则的名称,方便管理标识 |
break | 规则命中之后,是否跳出所有的规则集 |
状态 | 包括启用、关闭、测试三种状态 |
编辑 | 编辑规则 |
删除 | 删除规则 |
更多 | 包括启用、关闭、测试三个选项 |
规则优先级
理论上,所有规则的优先级是按照先后顺序来执行的,优先级越靠前则会被优先执行,这个仅适用于添加 HTTP 头部、删除 HTTP 头部、访问控制、请求限速、自定义错误页面、边缘重定向。针对 URL 改写动作,即使 URL 改写的规则放在前面, 还是会等执行完其他动作之后,才会去执行 URL 改写动作。
这里根据具体示例进行说明,如截图所示:
截图:后续添加
特别地:当匹配的条件都相同时,例如:当请求 URI 都为 /123.mp4 时,按照优先级顺序出现了如下 5 条规则:
第 1 条规则:当请求的 URI 为 /123.mp4 时,改写到 /beibei.mp4
第 2 条规则:当请求的 URI 为 /123.mp4 时,添加 HTTP 响应头 CDN
第 3 条规则:当请求的 URI 为 /123.mp4 时,边缘重定向到 https://www.upyun.com/
第 4 条规则:当请求的 URI 为 /123.mp4 时,进行访问控制,响应 403 状态码
第 5 条规则:当请求的 URI 为 /123.mp4 时,进行请求限速,限速到 200KB/s 。
按照当前的设计逻辑,第 1 条规则不会被立马执行,会等待后面所有的规则执行完毕之后,才会进行 URL 改写的动作。按照规则优先级,会依次执行第 2 条规则,然后再执行第 3 条规则,通过 curl 发起命令测试,测试结果为:
GET /123.mp4 HTTP/1.1
Host: wuxuejun2018.b0.upaiyun.com
User-Agent: curl/7.43.0
Accept: /< HTTP/1.1 302 Moved Temporarily
< Server: marco/1.10
< Date: Wed, 20 Dec 2017 09:28:28 GMT
< Content-Type: text/html
< Content-Length: 159
< Connection: keep-alive
< Location: https://www.upyun.com
< Via: M.ctn-zj-lna3-019
< X-Request-Id: 32c1c154c192027be98887ad63c3b08c
< CDN: UPYUN
按照测试结果,依次命中了第 2 条和 第 3 条规则。
可以看出,第 1 条、第 4 条、第 5 条都没有被执行,那是因为第 1 条属于 URL 改写,不会立马执行;第 3 条为边缘重定向,直接 302 到 https://www.upyun.com 了,跳出了整个规则集,从而接下来的规则不会被执行,包括 URL 改写。
特别注意的是,类似边缘重定向这类直接跳出所有规则集的行为,还包括:
也就是说,当执行完边缘重定向、自定义错误页面、访问控制等动作之后,会直接跳出整个规则集,不会执行接下来的匹配动作。
URI 字符串提取
所谓 URI 字符串提取,也即在执行边缘重定向以及 URL 改写动作时,根据业务需求,可能会提取原始请求 URI 中的字符串。其中 URI 字符串提取支持 PCRE 正则表达式,匹配后,产生 $1
, $2
... 这样的变量。
URI 字符串提取正则表达式:
^/pay/([0-9]+)/([0-9]+)/(.*?).html$
根据以上的 PCRE 正则表达式,分别会产生 3 个 字符串,为 $1
、$2
、$3
。分别对应了以上正则表达式里面的从左到右 ()
里面的字符串。
URL 改写规则:
/pay.php?payid=$1&categoryid=$2
通过执行以上规则之后,原始请求和改写后的地址分别如下:
原始请求:
http://example.com/pay/25/8/...
改写后地址:
http://example.com/pay.php?payid=25&categoryid=8...
变量使用
在进行 URL 改写和边缘重定向动作时,除了可以提取 URI 中的 字符串,您还可以获取原始请求中的变量。这些变量包括:
变量 | 含义 |
---|---|
$_IP |
客户端 IP |
$_HOST |
请求头中的 Host 字段 |
$_HOST_n |
$_HOST_n 指 Host 中的第 n 个子域,例如对于 foo.bar.baz.com:$_HOST_1 = foo,$_HOST_2 = bar,$_HOST_3 = baz |
$_GET_name |
使用 Query String 中的变量(无需 urldecode) |
$_POST_name |
使用 POST 表单中的变量(只支持 www form ) |
$_HEADER_name |
使用 Header 中的值,注意 name 全为小写 |
$_COOKIE_name |
使用 Cookie 中的字段值 |
$_RANDOM |
随机字符串,字符集为 [a-zA-Z0-9] ,默认 8 位 |
$_RANDOM_n |
n 位随机字符串,其中 1 <= n <= 32 |
$_URI |
请求的 URI,不包含参数 |
$_QUERY |
Query String,不带前缀 '?' |
$_METHOD |
GET/POST/PUT/POST/DELETE/OPTIONS/PATCH |
$_SCHEME |
http/https,注意此处全为小写 |
$_TIME |
获取当前服务器时间,格式为 UNIX TIME |
$_BODY |
获取当前请求的 BODY(请求体)内容,大小限制为 16KB |
$_GEOIP_COUNTRY_CODE |
国家代码,可参照维基百科: https://en.wikipedia.org/wiki/ISO_3166-2 |
为了更加方便理解,下面将通过一个应用示例来展开介绍:
示例:URL 改写
例如:某个 URL 为 https://www.example.com/index.htm
需求:希望通过 URL 改写动作,将客户端 IP(这里以 192.168.1.1 为例) 以及请求方法(实际的请求方法为 GET)通过查询字符串传递到源站后端;
改写规则可以为:
/index.php?ip=$_IP&method=$_METHOD
则改写后的完整 URL 为:
https://example.com/index.php?ip=192.168.1.1&method=GET
通过使用边缘规则的【添加 HTTP 头部】功能,当您的用户请求业务资源时,可以在返回的【响应消息】中添加您配置的头部,这些头部可能包括:
当然,您也可以根据业务要求,自定义响应字段。例如:CDN:UPYUN
具体使用截图如下:
截图:、、、
从截图可以看出,添加 HTTP 头部,您需要分别填写:
覆盖原有响应头:默认为否,可以根据具体情况来勾选。当勾选时,会覆盖掉原始的响应头信息。
规则测试