我正在尝试通过在 POST 路径的节点上强制执行 URL 编码来更正 URL 参数问题,这种情况经常发生。目前,似乎最好在代理层修复此问题,直到开发出更好的解决方案。但是 Haproxy 给我带来了这个问题,我还应该提到我目前只能使用 Haproxy v1.5(据我所知,它也将使用 Lua 排除在选项列表之外……在 v1.6 中引入了?)。
一个例子是这样的......
我通常会收到类似这样的 POST 请求。
http(s)://sub.domain.com/context/{context}/staticPath/location/{location}/material/{material}
因此,在实践中它可能看起来更像这样......
http://sub.domain.com/context/smith/staticePath/location/columbus/material/abc/123
需要从另一端进行以下操作......
http://sub.domain.com/context/smith/staticePath/location/columbus/material/abc%2F123
问题在于 abc/123 是一个单一材料,需要看起来更像“abc%2F123”,其中 '/' 斜杠正在改变实际路径。
我试图在代理中捕获这个问题,我可以使用正则表达式来捕获我需要的内容,但似乎每当我尝试在捕获组中使用“斜杠”'/'和/或尝试将斜杠放回替换部分时,它都会破坏重写。
这是我尝试过的例子,另外请记住,我打算扩大捕获范围以获取整个 url,但正在简化尝试解决这些问题,同时我正试图根据记忆讲述一些故事,所以如果下面的内容不准确,请原谅。我尝试了很多组合,试图想出一个可行的策略。
这样..
reqrep (\w+\s?)\/(material)\/(\w+\s?)\/(.*) \1\2\3%2f\4
我可以让捕获组将 URL 重新组合在一起,但是路径节点之间没有路径分隔符(“/”)。
这样,它就不会替换,它只会发送原始路径。
reqrep (\w+\s?)\/(material)\/(\w+\s?)\/(.*) \1\/\2\/\3%2f\4
采取这样的策略...
reqrep (\w+\s?)(\/)(material)(\/)(\w+\s?)\/(.*) \1\2\3\4\5%2f\6
我尝试的另一种策略是将“/”保留在捕获组中,以便它们可以在替换中出现,而不需要的“斜线”不会出现在捕获组中,类似于下面..
reqrep (\w+\s?)(\/material\/)(\w+\s?)\/(.*) \1\2\3%2f\4
我也读过并看到过一些例子,其中一些正则表达式有空格,而替换有一些空格......我可以通过在替换中使用一些空格来接近,但这会在最终结果中留下不需要的空格。
还..
如果我转义一个空格,然后添加一个斜线,它似乎更接近工作..例如\1\ /\2
但然后我会得到类似的结果(例如)location /material..
添加上面提到的空格。
我注意到的模式是,当我尝试将斜杠添加到正则表达式中的捕获组时,它会弄乱替换,让我对诸如此类的事情进行疯狂的猜测......斜杠没有被转义是因为它们在捕获组中吗?而且,为什么我不能将它们作为文字放回替换中?这就是我想象我可能偶然发现了一个错误的地方......但我也意识到我可能会搞砸这件事。已经使用 Nginx 开发了一个解决方案,但如果我可以让 Haproxy 做到这一点,那么在我们需要的东西前面放置一个实例也不是最实用的,主要是因为我们已经使用 Haproxy 做了很多其他事情了。
说实话,我更愿意用另一种方式来解决这个问题,但目前使用代理似乎是我最好的选择之一。我也没有能力强迫发起者提供更好的路径。
答案1
我在评论中提出的这个建议似乎几乎是正确的:
reqrep ^([^\ :]+)(\ ?/.+/material/)(.+)/(.+)(\ .+)$ \1\2\3\4%2f\5
事实上,我把它放在了\4
错误的一边%2f
。我还错误地将第二个捕获组开头的空格设为可选,这虽然不会破坏正则表达式,但从技术上讲并不正确。
这是正确的形式:
reqrep ^([^\ :]+)(\ /.+/material/)(.+)/(.+)(\ .+)$ \1\2\3%2f\4\5
这就是问题所在reqrep
——你直接调整 HTTP 请求的第一行。功能强大,但很乏味。
具体来说:
^
始终将你的图案固定于行首。
([^\ :]+)
这是 HTTP 动词(GET
、POST
等)。它不能包含空格,也不能包含冒号。这是捕获组 1。
(\ /.+/material/)
动词后面必须跟一个空格、前导斜杠(HAProxy 正则表达式中的正斜杠不需要反斜杠转义)、一个或多个字符,然后是 /material/...这是捕获组 2。
(.+)
我们想要拆分的第一部分/
是捕获组 3......实际上,([^/]+)
虽然大多数潜在的不匹配都被下面第 5 组所需的空间所阻止,但这样写会更正确。
/
我们要消除的斜线
(.+)
URL 中后面的部分/
是捕获组 4
(\ .+)
一个空格,后跟 1 个或多个字符,将HTTP/1.x
作为捕获组 5 在请求行的末尾捕获。
$
锚定在线的末端。
然后将它们重新组合在一起。
\1\2\3%2f\4\5
HAProxy 1.6 更优雅地处理了这个问题,它使用内置的 Lua 解释器以及一个名为的转换器regsub()
(虽然它非常简单——只有替换,没有捕获组,但它非常适合拆分字符串)和用户定义的变量,您可以在处理请求时“存储”小数据块。它还允许您使用http-request set-path
并具有一个path
提取功能,可以独立于 URL 的其余部分读取和写入路径,而无需直接使用正则表达式调整 HTTP 请求缓冲区。大多数或所有这些功能都不在 1.5 中。