MD5 $请求主体

MD5 $请求主体

我正在使用 nginx(和 OpenResty)并尝试$request_body对缓存进行哈希处理(使用缓存)。

当尝试echo,它$request_body运行完美:

# actually echoes the request body
location /works {
    # force loading the body
    echo_read_request_body;

    echo $request_body;
}

但是当尝试计算 md5 时,我得到的 MD5 是一个空字符串,尽管我确保$request_body是通过 加载的echo_read_request_body;

# echoes d41d8cd98f00b204e9800998ecf8427e, which is the MD5 for empty input.
location /doesnt-work-md5 {
    # force loading the body
    echo_read_request_body;

    set_md5 $digest $request_body;
    echo $digest;
}

最奇怪的现象是,它甚至在尝试复制变量:

# echoes nothing - empty data
location /doesnt-work {
    # force loading the body
    echo_read_request_body;

    set $temp $request_body;
    echo $temp;
}

顺便说一句,这些最新的代码片段在使用时不起作用$echo_request_body代替$request_body

提前致谢!

答案1

随着帮助OpenResty 的开发人员,我意识到set_XYZ(即setset_md5在 nginxrewrite阶段进行评估,而$request_body/$echo_request_body仅通过该阶段才可用content

因此,在评估时set_md5 $digest $request_body;$request_body变量为空,这解释了MD5结果的恒定性。

最终,我在自己的 API 应用程序中实现了实际的缓存键生成(见下面的示例),并使用access_by_lua堵塞。

区块在access阶段运行,在之前srcache_fetchsrcache_store进行评估(它们分别在post-access和中进行评估output-filter)。

在自己的 API 中实现它可以更好地控制缓存密钥生成逻辑,而这仅使用 nginx 很难做到(因为我不想成为一名成熟的 lua 程序员)。

例如,我希望能够确定性地带有 Json 主体的缓存POST请求。Json 序列化不是确定性的,因为键可以按任意顺序排列。在我的 API 中,我对键进行排序,因此对于相同的数据,生成的缓存键是恒定的。

此外,它简化了的处理$request_body,因为 lua 发出的子请求只是将其转发给 API,而不管阶段或磁盘缓冲状态。

最终配置如下

location /api {
    # proxy_pass ...
    # Force normal responses (no deflate, etc.) See https://github.com/openresty/srcache-nginx-module#srcache_ignore_content_encoding
    proxy_set_header  Accept-Encoding  "";

    set $cache_key "";
    access_by_lua_block {
        local res = ngx.location.capture('/generate-key' .. ngx.var.request_uri, {
                method=ngx.HTTP_POST,
                -- forwards the entire request body,
                -- regardless of disk buffering!
                always_forward_body=true,
                args=ngx.var.args
            })

        if res then
            ngx.var.cache_key = res.body
        end
    }

    # ... srcache options ...
}

location /generate-key {
    # proxy_pass ...
}

示例密钥生成API如下:

import flask
import json
import hashlib
import urllib


app = flask.Flask(__name__)

@app.route('/generate', defaults={'path': ''}, methods=['POST'])
@app.route('/generate/<path:path>', methods=['POST'])
def generate_cache_key(path):
    return urllib.quote('{}_{}_{}'.format(path,
        digest(stable_body()),
        digest(stable_json_dumps(flask.request.args))))


def stable_body():
    if flask.request.json:
        return stable_json_dumps(flask.request.json)

    return flask.request.data


def stable_json_dumps(data):
    return json.dumps(data, sort_keys=True)


def digest(data):
    return hashlib.md5(data).hexdigest()


if __name__ == '__main__':
    app.run()

答案2

我认为发生的情况是您在设置的位置运行多个模块时遇到了问题。但如果没有其余配置,我就不确定了。

您能将最后一个案例移至配置和测试的上方吗?

相关内容