如果条件在nginx配置中破坏了try_files

And*_*708 6 nginx

我的locationnginx配置中有一个简单的块,它匹配我网站的静态文件.我想要做的是检查文件是否存在try_files,如果不存在,则重定向到URL(在这种情况下,在@cdn位置块中指定).我还想设置一些CORS头.

以下是相关配置.

location ~* \.(css|js|jpe?g|png|gif|otf|eot|svg|ttf|woff|woff2|xml|json)$ {
    if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' "$http_origin";
        add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain charset=UTF-8';
        add_header 'Content-Length' 0;

        return 204;
    }

    if ($request_method = 'POST') {
        add_header 'Access-Control-Allow-Origin' "$http_origin";
        add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
    }

    if ($request_method = 'GET') {
        add_header 'Access-Control-Allow-Origin' "$http_origin";
        add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
    }

    try_files $uri @cdn;
}

location @cdn {
    return 301 https://example.com$request_uri;
}
Run Code Online (Sandbox Code Playgroud)

问题是,如果文件不存在,我得到404响应,而不是301重定向.在添加CORS头之前,配置工作正常.如果我删除了标题的处理,一切都按预期工作,我得到301响应.

现在我已经做了一些关于if指令为什么不好并且应该避免的解读,但我仍然不知道为什么它会破坏我的配置.如果我理解正确,它与任何一个if或与add_header重写模块或类似的东西有关,我猜这与之相冲突try_files.也许我在这里不准确,但无论哪种方式我都不确定如何解决它.

当找不到文件时,为什么存在if和/或add_header使nginx给我404而不是301,我该如何修复它?提前致谢!

M S*_*lle 6

http://agentzh.blogspot.co.uk/2011/03/how-nginx-location-if-works.html可能会让您对理解if工作原理感兴趣.在您的情况下,当if条件匹配时,请求现在在if上下文中提供,并且try_files不会被该上下文继承.或者作为https://www.digitalocean.com/community/tutorials/understanding-the-nginx-configuration-file-structure-and-configuration-contexts说"使用if上下文时要记住的另一件事是它呈现同一个上下文中的try_files指令没用."

此外,如果try_files回退到@cdn之前添加的任何标题都被遗忘,它会在新location块中再次启动,因此需要在那里添加标题.

至于如何解决它; 你可以在里面设置变量if,并add_header忽略一个空值,所以像这样的东西应该工作:

set $access-control-output 0;
location ~* \.(css|js|jpe?g|png|gif|otf|eot|svg|ttf|woff|woff2|xml|json)$ {
    set $access-control-output 1;
    try_files $uri @cdn;
}

set $acao = "";
set $acam = "";
if ($access-control-output) {
    set $acao = $http_origin;
    set $acam = "GET, OPTIONS";
}

map "$access-control-output:$request_method" $acma {
    "1:OPTIONS" 1728000; 
    default     "";
}

location @cdn {
    add_header 'Access-Control-Allow-Origin' $acao;
    add_header 'Access-Control-Allow-Methods' $acam;
    add_header 'Access-Control-Max-Age' $acma;
    return 301 https://example.com$request_uri;
}
Run Code Online (Sandbox Code Playgroud)

编辑:你不关心@cdn后备中的标题,在这种情况下你应该能够有这样的东西:

map $request_method $acma {
    "OPTIONS" 1728000; 
    default   "";
}

location ~* \.(css|js|jpe?g|png|gif|otf|eot|svg|ttf|woff|woff2|xml|json)$ {
    add_header 'Access-Control-Allow-Origin' $http_origin;
    add_header 'Access-Control-Allow-Methods' "GET, OPTIONS";
    add_header 'Access-Control-Max-Age' $acma;
    try_files $uri @cdn;
}

location @cdn {
    return 301 https://example.com$request_uri;
}
Run Code Online (Sandbox Code Playgroud)