MD5 $ request_body

1

Estou usando nginx (e OpenResty) e tentando alterar o $request_body para fins de cache (com srcache ).

Ao tentar apenas echo o $request_body , ele funciona perfeitamente:

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

    echo $request_body;
}

Mas ao tentar calcular o md5, recebo o MD5 de uma string vazia, embora eu garanta que o $request_body seja carregado via 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;
}

O fenômeno mais estranho é que nem funciona quando tentamos copiar a variável:

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

    set $temp $request_body;
    echo $temp;
}

A propósito, esses últimos snippets não funcionam ao usar $echo_request_body em vez de $request_body .

Obrigado antecipadamente!

    
por matan129 24.01.2018 / 23:40

2 respostas

3

Com a ajuda dos desenvolvedores do OpenResty, percebi que o set_XYZ (ou seja, set , set_md5 ) são avaliados durante a fase rewrite do nginx, enquanto o $request_body / $echo_request_body estão disponíveis somente através da fase content .

Portanto, ao avaliar set_md5 $digest $request_body; , a variável $request_body está vazia, o que explica o resultado constante da MD5.

Por fim, implementei a geração real de chaves de cache em meu próprio aplicativo de API (veja o exemplo abaixo) e acessei-o com access_by_lua bloquear.

O bloco é executado na fase access , antes de srcache_fetch e srcache_store são avaliados (eles avaliam em post-access e output-filter , respectivamente).

Implementá-lo em minha própria API permitiu maior controle sobre a lógica de geração de chave de cache, o que seria difícil de fazer com o nginx sozinho (já que eu não queria me tornar um programador lua completo).

Por exemplo, eu queria poder deterministicamente armazenar em cache as solicitações POST com corpos Json. A serialização de Json não é determinística, pois as chaves podem estar em qualquer ordem. Na minha API, eu classifico as chaves para que a chave de cache gerada seja constante para os mesmos dados.

Além disso, simplificou a manipulação do $request_body , já que o sub-tema emitido pela lua apenas o encaminha para a API, independentemente do status de buffer de fase ou de disco.

A configuração final parece

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 ...
}

A API de geração de chave de exemplo é a seguinte:

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()
    
por 25.01.2018 / 19:19
-1

Acho que o que está acontecendo é que você está tendo um problema com vários módulos em execução nos locais que você configurou. Sem o resto da sua configuração, não tenho certeza.

Você pode mover seu último caso para cima na configuração e no teste?

    
por 25.01.2018 / 00:15

Tags