【问题标题】:Converting mod_rewrite rules to nginx config - unexpected download instead of rewrite将 mod_rewrite 规则转换为 nginx 配置 - 意外下载而不是重写
【发布时间】:2017-01-03 10:37:55
【问题描述】:

我在搞乱 nginx 并试图将 mod_rewrite 规则转换为 nginx。到目前为止,我一直在使用以下内容:

RewriteEngine On
RewriteBase /
ErrorDocument 403 /HttpUnauthorized
ErrorDocument 404 /HttpNotFound

# Remove Trailing Slashes
RewriteCond %{REQUEST_METHOD} !=POST [NC]
RewriteCond %{REQUEST_URI} /$ [NC]
RewriteCond %{REQUEST_FILENAME} !-f [NC]
RewriteCond %{REQUEST_FILENAME} !-d [NC]
RewriteRule ^(.+)/$ $1 [NC,R=301,L]

# Removes index.php from URLs (actually this happens everywhere!)
RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC]
RewriteRule (.*?)index\.php/*(.*) $1$2 [R=301,NE,L]

# Directs all web requests through the site index file
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?q=/$1 [L,QSA]

我在网上找到的一个工具建议了以下输出:

error_page 404 /HttpNotFound;
error_page 403 /HttpUnauthorized;

location / {
    if ($request_method != "POST") {
        rewrite ^/(.+)/$ /$1 redirect;
    }
    rewrite (.*?)index\.php/*(.*) /$1$2 redirect;
    if (!-e $request_filename) {
        rewrite ^(.*)$ /index.php?q=/$1 break;
    }
}

而且(也许它也很重要)对于 PHP 我正在使用这个调用:

location ~ \.php$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass php-fpm:9000;
    fastcgi_param SCRIPT_FILENAME /var/www/html/$fastcgi_script_name;
    fastcgi_param PATH_INFO $fastcgi_path_info;
    fastcgi_index index.php;
    include fastcgi_params;
}

请求http://localhost/Foo 实际上是下载原始的index.php 源文件,但请求http://localhost/index.php?q=/Foo 会在浏览器中正确打开相应的站点并显示预期的输出。我的配置到底有什么问题?


尝试自定义规则后的一些问题

由于该工具的规则非常糟糕,我从一个基本的开始

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

我以前通过$_REQUEST['q'] 获得的查询字符串现在可以使用$_SERVER['REQUEST_URI'] 读取。所以我尝试使用

添加删除尾部斜杠
rewrite ^/(.+)/$ /$1 permanent;

不幸的是,在我的特定设置中,这两种方法都有效,但不能同时有效。我在 Docker 容器中运行 nginx,因此服务器在内部侦听端口 80,同时暴露在端口 8082 上。由于 nginx 认为它在端口 80 上运行(即使我通过http://localhost:8082/Foo/ 请求)它重写为http://localhost/Foo .除了让服务器首先监听正确的端口之外,还有什么方法可以处理这个问题?

【问题讨论】:

  • 我不确定是否能正确理解您对端口的评论。你的意思是重定向不再起作用了吗?或者 nginx 不知何故弄混了,认为查询实际上是针对另一个虚拟主机的?
  • @jwatkins 当我浏览到http://localhost:8082/Foo/ 时,我希望被重定向到http://localhost:8082/Foo,但我被重定向到http://localhost/Foo/,这与http://localhost:80/Foo/ 相同。由于我在配置中有一个listen 80,这是因为服务器显然没有注意到我正在从 Docker 公开的另一个端口访问它。因此,我只是考虑在 PHP 本身中处理更困难的重写/重定向。
  • 好的,这里有两点......首先,您不应该使用重定向来删除尾部斜杠。这会导致页面加载时间额外的完整往返损失,并且可以避免。其次,我记得通过添加额外的listen 80xx 语句解决了一个非常相似的问题;您不需要在 docker 容器上公开这些端口,但如果我没记错的话,nginx 会被此愚弄并停止尝试修复端口号。

标签: php apache .htaccess mod-rewrite nginx


【解决方案1】:

如果您的 PHP 文件被下载,它基本上表明 *.php 位置在这种情况下不匹配。那为什么不呢?

rewrite ... break 规则告诉 nginx 停止处理当前的重写规则集,但控制权仍保留在当前位置块内。这不是您想要的:您实际上希望 nginx 根据您计算的新 uri 重新评估位置。

尝试将break 关键字替换为last。这将告诉 nginx 必须开始新一轮,搜索修改后的 uri。

更新

在继续之前,试试这个非常简单的配置:

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

【讨论】:

  • 现在我没有下载,而是出现 404 错误(实际上正确显示,因此 /HttpNotFound 在内部正确重写为 /index.php?q=/HttpNotFound!)因为 http://localhost/Foo 似乎不在内部重写为预期的http://localhost/index.php?q=/Foo。我想我将不得不手动编写重写规则以匹配我以前的 Apache 规则。
  • 实际上,我绝不会推荐使用自动化工具将 Apache 重写规则转换为 nginx 配置。大多数 Apache 配置,甚至一些包含大量重写规则集的配置,都可以被非常简单、易于理解的 nginx 配置所取代。尤其是 try_files 指令,它是一个非常强大的工具,通常应该先尝试。
  • 确实,我注意到一行已经负责我的大部分内容,但是我还有另一个奇怪的问题,我将在稍后编辑我的问题。
  • 另外,if 指令在 nginx 社区中非常不受欢迎(参见nginx.com/resources/wiki/start/topics/depth/ifisevil)。有非常充分的理由尽可能避免它;遗憾的是,自动转换工具会建议围绕该结构组成的配置。
  • 感谢您迄今为止的输入 - 我实际上使用了我编辑中提到的简单配置。不幸的是,我在容器配置和端口管理方面有些挣扎。尽管如此,为 nginx 编写适当的重写规则似乎要容易得多。
猜你喜欢
  • 1970-01-01
  • 2012-08-25
  • 1970-01-01
  • 2014-06-30
  • 2016-08-09
  • 2016-06-18
  • 2018-03-28
  • 2012-07-22
  • 1970-01-01
相关资源
最近更新 更多