我正在尝试重新编写
等网址http://ourdomain.com/hotels/vegas?cf=0
到
http://ourdomain.com?d=vegas&cf=0
使用haProxy。
我们曾经使用
与Apache一起做RewriteRule ^hotels/([^/]+)/?\??(.*)$ ?d=$1&$2 [QSA]
我试过
reqrep ^([^\ :]*)\ /hotels/(.*) \1\ /?d=\2
但这给了我http://ourdomain.com?d=vegas?cf=0
和
reqrep ^([^\ :]*)\ /hotels/([^/]+)/?\??(.*) \1\ /?d=\2&\3
给我一个400错误。
用acl做它会很好,但我看不出它会如何起作用。
答案 0 :(得分:2)
reqrep ^([^\ :]*)\ /hotels/([^/]+)/?\??(.*) \1\ /?d=\2&\3
当给我一个400错误。
([^/]+)
之后的所有内容都是可选的时, /?\??(.*)
太贪心了。它正在破坏请求的最后部分,导致400。
记住您正在使用的数据类型:
GET /path?query HTTP/1.(0|1)
将([^/]+)
替换为([^/\ ]+)
,以便\3
而不是\2
捕获空间之后的任何内容。
更新:似乎上述情况并不完美,因为?
的对齐仍然无法解决。这个 - 以及最初的400错误 - 突出显示了req[i]rep
的一些陷阱 - 这是非常低级别的请求重复。
HAProxy 1.6引入了一些新功能,使请求调整更加清晰,这实际上是一个很好的例子来说明它们中的几个。请注意,这些示例还使用匿名ACL,包含在{
}
中。文档似乎不鼓励这些 - 但这只是因为当你因为多种原因需要测试同一组条件时它们难以维护(命名ACL当然可以更容易重用),但它们是'对于这样的案例非常完美。请注意,由于配置解析器限制,大括号必须至少包含1个空格字符。
变量,作用域请求(一旦选择了后端就超出范围),响应(仅在后端响应后进入范围),事务(从请求持久)为了响应,这些可以在到达后端之前使用,并且在响应返回时仍然在范围内)或会话(在此连接期间,如果浏览器重新使用连接,则此浏览器在多个请求的范围内),可用于存储值。
regsub()
转换器将前面的值作为输入,并返回通过简单的正则表达式替换传递的值。
如果路径以/hotels/
开头,则捕获路径,清除^/hotels/
(将其替换为下一个逗号后面出现的空字符串),并将其存储在名为{{的请求变量中1}}。
req.hotel
大多数http-request set-var(req.hotel) path,regsub(^/hotels/,) if { path_beg /hotels/ }
步骤的处理是按配置文件顺序完成的,因此,在下一条指令中,如果(且仅当)该变量具有值,我们使用 http-request
使用http-request set-path
参数清空路径。需要测试变量,这样我们就不会对每个请求执行此操作 - 只需要/ hotels /。可能你真的需要更像/
的东西,因为if { path_reg /hotels/.+ }
本身可能是我们应该留下的有效路径。
/hotels/
然后,我们使用 http-request set-path / if { var(req.hotel) -m found }
将查询字符串设置为通过将http-request set-query
变量的值与req.hotel
和原始查询相连接而创建的值字符串,我们使用 &
fetch 获得。
query
请注意,http-request set-query d=%[var(req.hotel)]&%[query] if { var(req.hotel) -m found }
fetch和query
都有一些神奇的行为 - 他们会照顾http-request set-query
。 ?
提取不会返回它,query
不希望您提供它。这很有用,因为我们可能需要能够正确处理请求,无论原始请求中是否存在http-request set-query
,而无需自行管理。
通过上述配置,?
变为GET /hotels/vegas?&cf=0 HTTP/1.1
。
如果初始查询字符串完全为空,则GET /?d=vegas&cf=0 HTTP/1.1
变为GET /hotels/vegas HTTP/1.1
。这看起来有点奇怪,但应该完全有效。一个稍微复杂的配置来测试初始查询字符串的存在可以防止这种情况,但我不认为这是一个问题。
所以,我们已经将1行配置变为3,但我认为这三行对于他们正在完成的事情更加直观,而且与按摩整个请求的起始行相比,这肯定是一个不太精细的操作。一个正则表达式。在这里,它们一起是一些可选的空格:
GET /?d=vegas& HTTP/1.1
答案 1 :(得分:0)
这是使用reqrep
acl is_destination path_beg /hotels/
reqrep ^([^\ :]*)\ /hotels/([^/\ \?]+)/?\??([^\ ]*)(.*)$ \1\ /?d=\2&\3\4 if is_destination
我希望acl不再需要在所有内容上运行正则表达式(因此稍微减轻了负载),但我不确定是不是这样。