是否存在等同于Apaches'{ENV:REDIRECT_STATUS}的Nginx环境变量?

时间:2015-04-17 09:01:44

标签: .htaccess nginx seo rewrite

从Apache迁移到Nginx时,.htaccess文件中的某些规则必须被翻译成“#”。到Nginx的配置文件。 我似乎无法解决的一个问题,一个例子是最简单的解释方法:

请求http://www.domain.com/nginx由Apache内部重写为index.php?option=com_content&view=article&id=145 现在我想阻止对index.php?option=com_content的直接请求,因此该页面仅通过http://www.domain.com/nginx可用,以避免重复内容。在Apache中,这是通过使用这些.htaccess规则实现的:

# Check if it's the first pass to prevent a loop. In case of first pass, the environment variable contains nothing 
# If http://www.domain.com/nginx already internally has been rewritten to index.php?option=com_content&view=article&id=145 {ENV:REDIRECT_STATUS} contains '200' and the request is allowed to be processed
RewriteCond %{ENV:REDIRECT_STATUS} ^$
# Check if the query string contains requests for the page
RewriteCond %{QUERY_STRING} ^index.php?option=com_content&view=article&id=145 [NC]
# If conditions apply, reject request
RewriteRule .* 404 [L]

在Nginx中,我可以使用这样的环境变量吗? 或者我应该以完全不同的方式处理这个问题?

编辑1: 在现实生活中,它不仅仅是一个页面,而是一个有很多页面的动态Joomla网站。我测试了上面哪个有效,但目的是阻止对index.php的所有请求?option_content& view = article& id = *

编辑2: 这是有效的NGINX配置文件:

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    root /usr/share/nginx/html/domainname;
    index index.php index.html index.htm;
    server_name domainname.com;

    server_name localhost;

    location / {
            try_files $uri $uri/ /index.php?$args;
    }

    # deny running scripts inside writable directories
    location ~* /(images|cache|media|logs|tmp)/.*\.(php|pl|py|jsp|asp|sh|cgi)$ {
             return 403;
             error_page 403 /403_error.html;
    }

    ## give 404 header & redirect to custom errorpage without changing URL ##
    error_page   404  =  /404_custom.php; #global error page, script handles header
    error_page 500 502 503 504 /50x.html;

    location =/index.php {
        set $arg_set "${arg_option}___${arg_view}___${arg_id}";
        if ($arg_set ~* "^(((\w|-)+?)___){2}((\w|-)+?)$") {
            return 404;
        }
            try_files $uri =404;
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass unix:/var/run/php5-fpm.sock;
            fastcgi_index index.php;
            include fastcgi_params;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php5-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }
}

1 个答案:

答案 0 :(得分:2)

Apache方法在这里不起作用,但是还有很多其他方法可以解决这个问题,具体取决于你要实现的规则数量以及其他一些条件。一般情况下,我会使用这样的东西:

map "${arg_option}___${arg_view}___${arg_id}" $show404 {
    default 0;

    # Put here the argument value sets of the pages 
    # you want to hide - one set per line
    "com_content___article___145" 1;
}

server {
    ...

    location /nginx {
        rewrite ^.*$ /index.php?option=com_content&view=article&id=145 break;
        proxy_pass ...
    }

    location =/index.php {
        if ($show404) {
            return 404;
        }

        proxy_pass ...;
    }

    ...
}

修改

如果你想阻止对index.php的所有请求,其中存在参数“option”,“view”和“id”,无论它们的值是什么,你都可以使用这样的东西:

location =/index.php {
    set $arg_set "${arg_option}___${arg_view}___${arg_id}";

    if ($arg_set ~* "^(((\w|-)+?)___){2}((\w|-)+?)$") {
        return 404;
    }

    proxy_pass ...
}

如果要检查这些参数的某些值,只需修改正则表达式以适合您的purpuse:

location =/index.php {
    set $arg_set "${arg_option}___${arg_view}___${arg_id}";

    if ($arg_set ~* "^com_content___article___(\d+)$") {
        return 404;
    }

    proxy_pass ...
}

此外,在您的情境中,可以使用map来简化配置,这样您就不必为每篇文章添加另一个位置,而是将所有重写规则封装在一个地图块中,如下所示:

map "$request_uri" $real_args {
    default "";

    "~*^/nginx"            option=com_content&view=article&id=145;
    "~*^/some_article"     option=com_content&view=news&id=123;
    "~*^/another_article"  option=com_content&view=article&id=515;
}

server {
    ...

    location / {
        if ($real_args) {
            rewrite ^.*$ /index.php?$real_args break;
        }

        proxy_pass ...
    }

    location =/index.php {
        # See above
    }

    ...
}

编辑2:

对于一两个例外情况,您可以使用negative look-ahead

来改善正则表达式
if ($arg_set ~* "^(((\w|-)+?)___){2}((?!175$)(\w|-)+?)$") {
    return 404;
}

但是如果你希望有很多这样的网址,那么你必须在你的配置中引入map。否则你的正则表达式会变得太复杂和难以管理。这种情况下的配置如下所示:

map "${arg_option}___${arg_view}___${arg_id}" $exception {
    default 0;

    "com_content___article___175" 1;
    "com_content___news___188" 1;
    "something___else___211" 1;
}

server {
    ...

    location =/index.php {
        set $arg_set "${arg_option}___${arg_view}___${arg_id}";

        if ($exception) {
            break;
        }

        if ($arg_set ~* "^(((\w|-)+?)___){2}((\w|-)+?)$") {
            return 404;
        }

        proxy_pass ...;
    }
    ...
}

这似乎有点违反直觉,但这就是“如果”在Nginx中如何运作。如果Nginx在第一个“if”块中遇到中断,则不会评估第二个“if”。