nginx – content-disposition file extension

I got a working /api/{UUID} served by a backend non controlled by me.
I need to add a /download/{UUID} the serves the same content, but saving a file with extension .json

i tried:

 location ~ "^/download/([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$" {
                rewrite /download/(.*) /api/$1  break;
                set $id $1;
                set $fname '${id}.json';
                add_header Content-Disposition 'attachment; filename="$fname"';
                proxy_pass http://localhost:8081;
        }

but the downloaded file is always missing the extension.
what I’m doing wrong?

>Solution :

The reason is the order of directives from the ngx_http_rewrite_module. While by most parts nginx config is declarative, directives from the rewrite module are imperative ones and being executed in order of appearance. That break flag from the rewrite directive makes nginx to stop executing any further directives from the rewrite module, which makes your set statements never get executed at all. You can change the order of those directives:

location ~ "^/download/([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$" {
    set $id $1;
    set $fname '${id}.json';
    rewrite /download/(.*) /api/$1  break;
    add_header Content-Disposition 'attachment; filename="$fname"';
    proxy_pass http://localhost:8081;
}

However I think it would be simpler to use named captures:

location ~ "^/download/(?<id>[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$" {
    rewrite ^ /api/$id  break;
    add_header Content-Disposition 'attachment; filename="$id.json"';
    proxy_pass http://localhost:8081;
}

Or even this:

location ~ "^/download/(?<id>[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$" {
    add_header Content-Disposition 'attachment; filename="$id.json"';
    proxy_pass http://127.0.0.1:8081/api/$id;
}

(I used 127.0.0.1 here instead of localhost or this configuration would require a resolver to resolve the localhost hostname to 127.0.0.1 IP address. Yeah, sometimes using localhost instead of 127.0.0.1 makes some things different.)

Leave a Reply