如何使用 HAProxy 发送响应而不将请求传递给 Web 服务器

Posted

技术标签:

【中文标题】如何使用 HAProxy 发送响应而不将请求传递给 Web 服务器【英文标题】:How to send a response with HAProxy without passing the request to web servers 【发布时间】:2014-12-20 19:38:02 【问题描述】:

由于 CORS(跨域资源共享),服务器正在接收数千个 OPTIONS 请求。现在,每个选项请求都被发送到其中一个服务器,这有点浪费,因为知道 HAProxy 可以在没有 Web 服务器帮助的情况下自己添加 CORS 标头。

frontend https-in
    ...
    use_backend cors_headers if METH_OPTIONS
    ...

backend cors_headers
    rspadd Access-Control-Allow-Origin:\ https://www.example.com
    rspadd Access-Control-Max-Age:\ 31536000

但是,要使其正常工作,我需要在 cors_headers 后端指定至少一个实时服务器,并且该服务器仍会接收请求。

如何在不指定任何服务器的情况下在后端处理请求?如何停止将请求传播到服务器,同时将响应发送到浏览器并保持连接处于活动状态?

【问题讨论】:

我也想做同样的事情,你能做到吗? 【参考方案1】:

为 HAProxy 2.2 及更高版本编辑:如果您需要支持来源白名单,Lua 脚本现在可以生成整个响应,而无需将请求传递给后端服务器。可以在此处找到带有简单集成说明的示例 Lua 脚本:https://github.com/haproxytech/haproxy-lua-cors

在 HAProxy 1.5.14 中执行此操作的唯一方法是手动触发 503 错误(没有可用于处理请求的服务器)并将错误页面设置为带有自定义 CORS 标头的文件。

backend cors_headers
    errorfile 503 /path/to/custom/file.http

file.http 应包含所需的标题和末尾的 2 个空行

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.example.com
Access-Control-Max-Age: 31536000
Content-Length: 0
Cache-Control: private


<REMOVE THIS LINE COMPLETELY>

这种“方法”有几个限制:

在发送 CORS 标头之前无法检查来源,因此您要么必须拥有允许来源的静态列表,要么必须允许所有来源

缺少动态标题:你不能这样做

http-response set-header Date %[date(),http_date]

或设置Expires 标头。

注意:如果您随着时间的推移动态更新 HTTP 文件,要将更改应用到 HAProxy,您必须重新启动它。它可以是优雅重启或硬重启,在任何一种情况下,新文件都将被加载、缓存并立即提供服务。

【讨论】:

haproxy 2.2 添加了允许设置响应的http-request return 指令。不需要 Lua。【参考方案2】:

好消息,HAProxy 2.2 just introduced“本机响应生成器”功能。它与http-request return 指令配合使用,可用于提供静态文件或文本字符串,包括动态参数。 目标是避免使用errorfile 进行常见的黑客攻击。

利用 2.2 版中引入的另一个指令 (http-after-response),可以通过以下方式实现 OP 目标:

backend cors_headers
    # http-response won't work here as the response is generated by HAP
    http-after-response set-header Access-Control-Allow-Origin \
        "%[req.hdr(Origin)]"
    http-after-response set-header Access-Control-Max-Age "31536000"
    http-request return status 200 content-type "text/plain" string "" if TRUE

set-headerhttp-request return 可以根据您的需要使用基于请求标头或来源的if 子句来设置条件(有关示例,请参见文档)。

通过这种技术,标头和响应可以使用变量:

http-request return status 200 content-type "text/plain" \
    lf-string "Hello, you are: %[src]"

【讨论】:

这非常接近于解决我试图解决的另一个问题,但我使用的是 haproxy 2.1.7 :(

以上是关于如何使用 HAProxy 发送响应而不将请求传递给 Web 服务器的主要内容,如果未能解决你的问题,请参考以下文章

如何访问对象而不将其作为参数传递?

如何将一些信息传递给视图而不将其包含在 URL 中(django 新手)

Codeception 助手使用 $I 而不将其传递给助手

如何自动将用户信息传递给 Bot Framework 对话实例,而不将其作为显式消息发布在聊天窗口中?

如何在保留元数据的同时转发电子邮件而不将电子邮件重新发送给抄送收件人?

在 CUDA 中查找 max/min 而不将其传递给 CPU