nginx:在重写的位置块中指定自定义标头

Eti*_*rot 5 http configuration nginx cache http-headers

我正在尝试仅为locationnginx 中的特定块设置一些标头。

我遇到的问题是这些location块包含rewrite语句,显然似乎删除了自定义标题。

在这个例子中,我有两个我想要的规则:

  • 里面的文件/static应该有expires max;(它设置标题Cache-Control: max-age=some huge valueExpires: some future date really far off),并将它们的名字重写为不包含的内容/static
  • 其他地方的文件都应该有Cache-Control: public(没有max-age

这是我尝试的配置:

server {
    listen [::]:80;
    root /somepath;
    location /static {
        expires max;
        rewrite /static(.*) /whatever$1;
    }
    add_header Cache-Control public;
}
Run Code Online (Sandbox Code Playgroud)

并具有以下目录结构:

/somepath
/somepath/f1.txt
/somepath/static/f2.txt
Run Code Online (Sandbox Code Playgroud)

然后我们得到以下信息:

  • f1.txt: Cache-Control: public, 没有Expires标题
  • f2.txt: Cache-Control: public, 没有Expires标题

这对f1.txt但无效f2.txt。我希望它是这样的:

  • f1.txt: Cache-Control: public, 没有Expires标题
  • f2.txt: Cache-Control: max-age=some huge value,Expires: some future date really far off

我认为,问题源于这一rewrite /static(.*) /whatever$1;行,这使得 nginx 取消迄今为止添加的标头,然后再次添加它们(从而重新添加Cache-Control)。因此,一个简单的解决方法是:

server {
    listen [::]:80;
    root /somepath;
    location /static {
        rewrite /static(.*) /whatever$1;
    }
    location /whatever {
        expires max;
    }
    add_header Cache-Control public;
}
Run Code Online (Sandbox Code Playgroud)

问题是在我的真实配置文件中,它rewrite看起来并不那么友好。重写的 URL不容易以某种方式匹配,也不会匹配某些不应该具有 的文件expires max,因此我无法真正使用此解决方法。

有没有办法让这些标题在 a 之后粘住rewrite

编辑:这是我的真实 URL 的样子:

location ~ /(?:posts-)?img/.*-res- {
    access_log               off;
    expires                  max;
    rewrite                  "/img/(.*)-res-.{8}(.*)" /img/$1$2;
    rewrite                  "/posts-img/(.*)-res-.{8}(.*)" /posts/$1$2;
}
Run Code Online (Sandbox Code Playgroud)

虽然我可以添加一个 location/img来处理使用第一个rewrite规则重写的文件,但我不能为第二个 ( /posts)块,因为其中的某些文件/posts不是可缓存的资源,因此不应该包含expires max.

编辑 2:完整配置(或至少包含所有相关部分):

server {
    listen [::]:80;
    root /somepath;
    server_name domain.tld;
    location ~ /(?:posts-)?img/.*-res- {
        access_log               off;
        expires                  max;
        rewrite                  "/img/(.*)-res-.{8}(.*)" /img/$1$2;
        rewrite                  "/posts-img/(.*)-res-.{8}(.*)" /posts/$1$2;
    }
    add_header Cache-Control public;
}
Run Code Online (Sandbox Code Playgroud)

目录结构:

/somepath
/somepath/img/f1.png
/somepath/posts/post1.html
/somepath/posts/d1/f2.png
/somepath/posts/d2/f2.png
Run Code Online (Sandbox Code Playgroud)

根据 HTTP 请求的预期行为:

  • GET /somepath: 供应 /somepathCache-Control: public
  • GET /somepath/img/f1.png: 供应 /somepath/img/f1.pngCache-Control: public
  • GET /somepath/img/f1-res-whatever.png: 供应 /somepath/img/f1.png与发送的标头一起提供expires max
  • GET /somepath/posts/post1.html: 供应 /somepath/posts/post1.htmlCache-Control: public
  • GET /somepath/posts/d1/f2.png: 供应 /somepath/posts/d1/f2.pngCache-Control: public
  • GET /somepath/posts-img/d1/f2-res-whatever.png:/somepath/posts/d1/f2.png与发送的标头一起提供expires max

sen*_*nfo 2

这应该可行(不过我用更简单的配置验证了这一点)。顺便说一句,Igor Sysoev 建议尽可能少地使用正则表达式位置。

    location /img {
        if ($arg_max) { expires max; }
        ...
    }

    location /posts-img {
        if ($arg_max) { expires max; }
        ...
    }

    location ~ /(?:posts-)?img/.*-res- {
        access_log               off;
        expires                  max;
        rewrite                  "/img/(.*)-res-.{8}(.*)" /img/$1$2?max=1;
        rewrite                  "/posts-img/(.*)-res-.{8}(.*)" /posts/$1$2?max=1;
    }
Run Code Online (Sandbox Code Playgroud)