2015-04-17 37 views
1

从Apache迁移到Nginx时,.htaccess文件中的某些规则必须'转换'为Nginx的配置文件。 一个问题,我似乎无法来解决,一个例子是解释最简单的方法:是否存在与Apaches的{ENV:REDIRECT_STATUS}等效的Nginx环境变量?

请求http://www.domain.com/nginx在内部被阿帕奇改写为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 &视图=文章& 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; 
    } 
} 
+0

有指令'内部'http://nginx.org/r/internal –

回答

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,其中参数“选项”,“查看”和“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 "$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; 
} 

但是,如果你期望有很多这样的URL,你必须在你的配置中引入地图。否则,你的正则表达式会变得太复杂和难以管理。在这种情况下,配置是这样的:

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”。

+0

谢谢你的答案。我给出的例子是为了清晰起见而简化了这个过程。在现实生活中,这不仅仅是一个页面,而是一个拥有大量页面的动态网站。我测试了上述哪些工作,但其目的是阻止index.php上的所有请求?option_content&view = article&id = * 这可以通过map完成吗? –

+1

@cavuyk在这种情况下,你根本不需要使用地图。只需根据适当的正则表达式检查您的请求参数,并在匹配的情况下返回404。我已经更新了原来的答案。 –

+0

这个配置的工作原理(上面发布的问题),你的回答接受,谢谢。但是,我还不明白为什么index.php上的直接请求被阻止,而CMS仍然可以使用index.php。是否可以描述内部处理,以便我能够理解它? –