我正在使用 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
(即set
)set_md5
在 nginxrewrite
阶段进行评估,而$request_body
/$echo_request_body
仅通过该阶段才可用content
。
因此,在评估时set_md5 $digest $request_body;
,$request_body
变量为空,这解释了MD5结果的恒定性。
最终,我在自己的 API 应用程序中实现了实际的缓存键生成(见下面的示例),并使用access_by_lua
堵塞。
区块在access
阶段运行,在之前srcache_fetch
和srcache_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
我认为发生的情况是您在设置的位置运行多个模块时遇到了问题。但如果没有其余配置,我就不确定了。
您能将最后一个案例移至配置和测试的上方吗?