向 nginx 中上游服务器的响应添加自定义标头

问题描述 投票:0回答:1

我正在尝试根据响应正文向 Nginx 中上游服务器的响应添加自定义响应标头。

为了简单起见,让这个自定义标头成为响应正文的 SHA1 哈希值。为了实现这一目标,我尝试使用 Nginx 的 njs 脚本模块。

我参考了 njs-examples 存储库中的示例。然而,这些示例将标题和正文部分分开处理,我正在努力将它们组合起来以实现我的目标。

这是我当前的配置:

# nginx.conf

load_module modules/ngx_http_js_module.so;

events {}

http {
    js_path "/etc/nginx/njs/";
    js_import main from hello.js;  

    # Configuration containing list of application servers
    upstream app_servers {
        server flask:5000;
    }

    server {
        listen 80;
        server_name localhost;

        location / {
            js_body_filter main.hello;
            proxy_pass http://app_servers/;
        }
    }
}
# hello.js

function hello(r, data, flags) {
    var val = data.length;
    ngx.log(1, val);
    r.headersOut["X-Hello"] = val;
    r.sendBuffer(data, flags);
}

export default { hello };

但是,当我向 Nginx 服务器发送请求时,我在响应中看不到

X-Hello
标头。

有没有办法在 Nginx 中使用 njs 脚本来实现我的用例?如果没有,我应该考虑哪些替代方法,例如实现自定义 Nginx 模块?任何有关如何进行的建议或指导将不胜感激。

PS:我正在 Docker 容器上运行此设置,其中包含官方 nginx 映像以及一些用于热重载的脚本。如果需要的话,我也可以分享

Dockerfile
docker-compose.yml

nginx nginx-reverse-proxy njs
1个回答
0
投票

Liam Crilly 在 Nginx 社区 slack 上回答。

这可能行不通,因为 NGINX 会发送响应 在读取整个正文之前向客户端发送标头。所以到时候 你已经阅读了响应正文,现在再修改就太晚了 标题。

您可以尝试使用

js_header_filter
函数(使用
res.length
)但正如我所说,标头已经在 身体已收到。我认为这不会起作用

再次思考这一点。你可以用预告片来做到这一点,只要 客户接受了。

使用

js_header_filter
切换到分块 传输编码,删除内容长度标头,并定义一个 预告片。

使用

js_body_filter
收集并散列正文,发送 body,然后发送我们上面定义的预告片中的哈希值。

好吧,所以我不能让这个下降:lolsob:这是一个解决方案,添加了一个 作为预告片的响应的 SHA-1 哈希值。不确定这是否能解决您的问题 问题,@Gaurav Jain,但我很高兴找到答案!

nginx.conf
片段

js_import conf.d/body.js;
js_set $body_hash body.get_hash;

server {
    listen 80;
    location / {
        proxy_pass http://localhost:9001;
        js_body_filter body.set_hash;
        add_trailer Body-Hash $body_hash;
    }
}

server {
    listen 9001;
    root /usr/share/nginx/html;
}

body.js

var hash = "";
var res = "";
var buf = 0;
function set_hash(r, data, flags) {
    if (data.length) buf++;
    res += data;      // Collect the entire response,
    if (flags.last) { //  until we get the last byte.
        try {
            hash = require('crypto').createHash('sha1').update(res).digest('base64');
            r.sendBuffer(res, flags);
            ngx.log(ngx.INFO, `FILTERED ${res.length} bytes in ${buf} buffers`);
        } catch (e) {
            ngx.log(ngx.ERR, `ERROR ${e}`);
            r.sendBuffer("", flags);
        }
    }
}

function get_hash() {
    return hash;
}

export default { set_hash, get_hash }

Test

curl -i localhost
HTTP/1.1 200 OK
Server: nginx/1.25.2
Date: Wed, 13 Sep 2023 21:38:25 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
Last-Modified: Tue, 15 Aug 2023 17:03:04 GMT
ETag: "64dbafc8-267"
Accept-Ranges: bytes

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Body-Hash: xRo/Dm3k64AtVjCUHD/Z4dDvrks=
© www.soinside.com 2019 - 2024. All rights reserved.