策略扩展—用例

某些客户应用程序具有现有策略和表达式无法解决的需求。策略扩展特性允许客户向其应用程序添加定制功能,以满足他们的需求。

下面的用例说明了如何使用Citrix ADC设备上的策略扩展特性添加新功能。

  • 案例1:自定义哈希
  • 案例2:在URL中折叠双斜杠
  • 案例3:联合收割机收割台

案例1:自定义哈希

自定义_散列函数提供了一种机制,可以在发送给客户端的响应中插入任何类型的散列值。在本用例中,散列函数用于计算重写HTTP请求的查询字符串的散列,并插入名为CUSTOM_HASH的HTTP头和计算出的值。自定义_散列函数实现DJB2散列alg算法。

CUSTOM_HASH的示例用法:

> add rewrite action test_custom_hash insert_http_header "CUSTOM_HASH" "HTTP.REQ.URL.QUERY. "CUSTOM_HASH“< !——NeedCopy >

CUSTOM_HASH()的定义示例:

--扩展函数计算文本上的自定义哈希——使用djb2字符串哈希算法函数NSTEXT:custom_hash():NSTEXT local hash=5381 local len=string.len(self)for i=1,len do hash=bit32.bxor((hash*33),string.byte(self,i))end返回字符串(hash)end<!--NeedCopy-->

上述示例的逐行描述:

定义CUSTOM_HASH()函数,带有文本输入和文本返回值。local len = string.len(self)声明两个本地变量:累积计算哈希值并以数字5381 - len作为种子。设置为self输入文本字符串的长度,使用内置的string.len()函数。对于I = 1, len do hash = bit32。Bxor ((hash * 33)),字符串。end遍历输入字符串的每个字节,并将该字节添加到哈希中。它使用内置的string.byte()函数获取字节,使用内置的bit32.bxor()函数计算现有哈希值(乘以33)和字节的XOR。调用内置的tostring()函数将数值哈希值转换为字符串,并将字符串作为函数的值返回。<!——NeedCopy >

案例2:在URL中折叠双斜杠

折叠URL中的双斜杠可以缩短网站呈现时间,因为浏览器更高效地解析单斜杠URL。单斜杠URL还可以保持与不接受双斜杠的应用程序的兼容性。策略扩展功能允许客户添加一个函数,该函数将URL中的双斜杠替换为单斜杠。下面的示例演示了添加的策略扩展函数,该函数可折叠URL中的双斜杠。

COLLAPSE_DOUBLE_SLASHES()的示例定义:

——将URL中的双斜杠折叠为一个斜杠,并返回结果函数NSTEXT:COLLAPSE_DOUBLE_SLASHES(): NSTEXT local result = string。Gsub (self, "//", "/")返回结果end 

上述示例的逐行描述:

函数NSTEXT:COLLAPSE_DOUBLE_SLASHES(): NSTEXT声明带有文本输入和返回的COLLAPSE_DOUBLE_SLASHES()函数。本地结果=字符串。gsub(self, "//", "/")声明一个名为result的局部变量,并使用内置的string.gsub()函数将self输入文本中的所有双斜杠替换为单斜杠。gsub()的第二个参数实际上是一个正则表达式模式,不过这里的模式使用了一个简单的字符串。return result返回结果字符串。<!——NeedCopy >

案例3:联合收割机收割台

某些客户应用程序无法处理请求中的多个标头。同样,解析具有相同报头值的重复报头,或者在请求中解析具有相同名称但不同值的多个报头,会消耗时间和网络资源。策略扩展特性允许客户添加一个函数,将这些头合并为单个头,并使用一个值组合原始值。例如,合并标题H1和H2的值。

原始请求:

GET /combine_headers HTTP/1.1 User-Agent: amigo unit test Host: myhost H2: h2val1 H1: abcd Accept: */* H2: h2val2 Content-Length: 0 H2: h2val3 H1: 1234 

修改请求:

GET /combine_headers HTTP/1.1 User-Agent: amigo unit test Host: myhost H2: h2val1, h2val2, h2val3 H1: abcd, 1234 Accept: */* Content-Length: 0 

通常,这种类型的请求修改是使用Rewrite特性完成的,使用策略表达式来描述要修改的请求部分(目标)和要执行的修改(字符串生成器表达式)。但是,策略表达式不能遍历任意数量的头文件。

此问题的解决方案需要对策略工具进行扩展。为此,我们将定义一个名为COMBINE_HEADERS的扩展函数。使用此函数,我们可以设置以下重写操作:

> add rewrite action combine_headers_act replace 'HTTP. req . full_header . after_str ("HTTP/1.1rn")' 'HTTP. req . full_header . after_str ("HTTP/1.1rn").COMBINE_HEADERS'

这里,重写目标是HTTP.REQ.FULL_HEADER.AFTER_STR(“HTTP/1.1rn”)。需要AFTER_STR(“HTTP/1.1rn”),因为FULL_头包括HTTP请求的第一行(例如GET/combine_头HTTP/1.1)。

字符串生成器表达式是HTTP. req . full_header . after_str (" HTTP/1.1rn ")。COMBINE_HEADERS, where the headers (minus the first line) are fed into the COMBINE_HEADERS extension function, which combines and returns the values for headers.

COMBINE_HEADERS()的定义示例:

——扩展函数将多个相同名称的头文件合并为一个头文件。function NSTEXT:COMBINE_HEADERS(): NSTEXT local headers ={}——headers local combined_headers ={}——带有最终组合值的头文件——迭代遍历每个头文件(format "name:valuer\r\n")——并为每个唯一的头文件名称构建一个值列表。对于名称,值在字符串中。Gmatch (self, "([^:]+):([^\r\n]*)\r\n") do if headers[name] then local next_value_index = #(headers[name]) + 1 headers[name][next_value_index] = value else headers[name] = {name ..”:“. .Value} end end——遍历报头,并用分隔符","连接报头的值,成对的值(报头)做local next_header_index = #combined_headers + 1 combined_headers[next_header_index] = table。concat(values, ",") end——使用table.concat() local result_str = table构造结果头。concat (combined_headers“\ r \ n”)。"\r\n\r\n"返回result_str end 

上述示例的逐行描述:

定义COMBINE_HEADERS扩展函数,包含从策略表达式到函数的文本输入和策略表达式的文本返回类型。声明局部变量header和combined_headers,并将这些变量初始化为空表。头文件将是一个字符串数组表,其中每个数组保存一个头文件的一个或多个值。Combined_headers将是一个字符串数组,其中每个数组元素都是包含其组合值的头文件。对于名称,值在字符串中。Gmatch (self, "([^:]+):([^\r\n\]*)\r\n")做…结束< !——NeedCopy >

这个通用for循环解析输入中的每个头。迭代器是内置的string.gmatch()函数。此函数接受两个参数:一个用于搜索的字符串和一个用于匹配字符串片段的模式。要搜索的字符串由隐式self参数提供,该参数是输入函数的标题文本。

该模式使用正则表达式(简称regex)表示。这个regex匹配每个报头的名称和值,HTTP标准定义为的名字价值\ r \ n。regex中的括号指定要提取的匹配部分,因此regex示意图为(匹配名称):(匹配值)\r\n。这个匹配名称模式需要匹配除冒号以外的所有字符。这是写为[^::+([^:]是除:+以外的任何字符,+是一个或多个重复)。类似地匹配值Pattern必须匹配除\r\n之外的任何字符,所以它写成[^\r\n]([^\r\n]匹配除\r和\n之外的任何字符,*为零或多次重复)。这使得完整的正则表达式([^:]+):([^\r\n])\r\n。

for语句使用多重赋值来为string.gmatch()迭代器返回的两个匹配项设置name和value。在for循环的循环体中,这些变量被隐式声明为局部变量。

如果headers[name] then local next_value_index = #(headers[name]) + 1 headers[name][next_value_index] = value else headers[name] = {name ..”:“. .结束值}< !——NeedCopy >

for循环中的这些语句将头名称和值放入headers表中。第一次解析头名称时(在示例输入中为H2:h2val1),该名称没有头条目,头[name]为nil。

由于nil被视为false,因此执行else子句。这会将name的headers条目设置为具有一个字符串值的数组的名字价值。

注意:else循环中的数组构造函数等价于{[1]= name ..”:“. .Value}设置数组的第一个元素。)对于第一个H2头,它设置headers[" H2 "] = {" H2:h2val1 "}。

在头的后续实例上(例如,在示例输入中为H2:h2val2)。头[name]不是nil,因此执行then子句。这将确定头[name]数组值中的下一个可用索引,并将头值放入该索引中。对于第二个H2头,它设置头[“H2”]={“H2:h2val1”,“h2val2”}。

对于名称,成对的值(标题)执行本地下一个(标题)索引=#组合(标题)+1个组合(标题)[下一个(标题)索引]=table.concat(值,“,”)end<!--NeedCopy-->

在解析原始头并填写headers表之后,此循环将构建组合的_头数组。它使用pairs()函数作为for循环迭代器。

每次调用pairs()都会返回headers表中下一个条目的名称和值。

下一行确定组合标题数组中的下一个可用索引,下一行将该数组元素设置为组合标题。它使用内置表。concat()函数,它将字符串数组和用作分隔符的字符串作为其参数,并返回由分隔符分隔的数组字符串的串联字符串。

例如,对于values = {" H2:h2val1 ", " h2val2 "},将生成" H2:h2val1, h2val2 "

本地结果\u str=table.concat(组合的\u头,“\r\n”)..“\r\n\r\n”<!--NeedCopy-->

在构建了combined_headers数组之后,它将元素连接到一个字符串中,并添加一个双\r\n来终止HTTP头。

返回result_str < !——NeedCopy >

返回一个字符串作为COMBINE_HEADERS扩展函数的结果。

策略扩展—用例