最近我们从 Apache 迁移到了 Nginx,在 Apache 下这曾经非常容易,只需将一些内容放在 .htaccess 上即可。
RewriteEngine on
RewriteBase /
# only rewrite if the requested file doesn't exist
RewriteCond %{REQUEST_FILENAME} !-s
# pass the rest of the request into index.php to handle
RewriteRule ^(.*)$ /index.php/$1 [L]
上述操作对于清理 URL 并让 index.php 处理所有请求非常有用。但在 Nginx 中,我们需要重写位置块中的每个唯一 URL。然而,这并不像 apache 那样“自动”。
我们的重写位置块的一些示例
location / {
try_files $uri $uri/ /index.php;
}
location /p {
rewrite ^/p(?:/([a-z_]+))?$ /index.php?p=$1 last;
rewrite ^/p/all_articles/user/(.*)?$ /index.php?p=all_articles&user=$1 last;
try_files $uri $uri/ /index.php;
}
location /about_us {
rewrite ^/about_us /index.php?about_us last;
try_files $uri $uri/ /index.php;
}
location /search {
rewrite ^/search/(.*) /index.php?search=$1;
rewrite ^/search/(.*)/page/(.*)?$ /index.php?search=$1&page=$2 last;
try_files $uri $uri/ /index.php;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
上面的代码在清理 URL 时做得很好,但是当我们需要获取页面时
/p/all_articles/用户/ABC/页/2
/index.php?p=all_articles&user=ABC&page=2
我们已经尝试过了
rewrite ^/p/all_articles/user/(.*)/pg(?:/([0-9]+))?$ /index.php?p=all_articles&user=$1&pg=$2 last;
这仅当我们放置在单独的位置块时才有效
location /page/all_articles {
rewrite ^/p/all_articles/user/(.*)/pg(?:/([0-9]+))?$ /index.php?p=all_articles&user=$1&pg=$2 last;
try_files $uri $uri/ /index.php;
}
并且当这样做时,它不会让
/p/all_articles/用户/ABC
加载。
此外,搜索结果页面根本不起作用。
我们遇到的另一个问题是文件夹 .htaccess
Order deny,allow
Deny from all
Options -Indexes
在 Apache 下,这将阻止除 php 脚本之外对该文件夹和文件的任何访问。我们尝试过,
location /(data|img)/ {
deny all;
return 404;
}
它确实会阻止对文件夹的访问,但是,如果您指定文件名,它仍然会提供服务,例如不会拒绝访问;
/data/backup_01012020.zip 在 apache .htaccess 下,只有某些用户在登录后才被允许访问。而在它之外,apache 将拒绝任何访问。但在 nginx 下,即使在尝试访问 /data/ 时也会给出 404。即使您未登录,它也会立即提供 backup_01012020.zip 文件。
现在我们不知道该做什么,以前使用 apache 很容易。我们的应用程序基于 PHP,index.php 能够处理所有干净的 URL 请求。如果 Nginx 只是将所有请求传递给索引并让它处理,而不是进行大量的重写和位置块,那就太好了。任何帮助都很好。
答案1
您可能对以下问题感兴趣重写标签,因为它包含了您的问题的许多变体。
您的 Apache 重写规则:
RewriteRule ^(.*)$ /index.php/$1 [L]
将整个请求 URI 附加到/index.php
。在nginx这小路URI(规范化)可在$uri变量。如果您也需要查询参数,则可以使用$请求uri反而。
因此,重写规则的严格翻译将是:
location / {
# Size zero static files are served.
# I don't believe that is an issue.
try_files $uri /index.php$request_uri;
}
# If no other .php files are accessible a prefix location of '/index.php/'
# is safer.
location /index.php/ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
# Probably duplicates the contents of fastcgi-php.conf
# fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# include fastcgi_params;
}
您deny
对位置的指令/(data|img)/
不起作用,因为您使用的是前缀匹配,而不是正则表达式匹配:
location ~ ^/(data|img)/ {
# Only one is required
deny all;
# return 404;
}
答案2
重写的解决方案
location /search {
rewrite ^/search/(.*)/page/(.*)?$ /index.php?search=$1&page=$2 last;
rewrite ^/search/(.*) /index.php?search=$1 last;
try_files $uri $uri/ /index.php;
}
location /p/all_articles {
rewrite ^/p/all_articles/user/(.*)/page(?:/([0-9]+))?$ /index.php?p=all_articles&user=$1&page=$2 last;
rewrite ^/p/all_articles/user/(.*)?$ /index.php?p=all_articles&user=$1 last;
try_files $uri $uri/ /index.php;
}
注意,我所做的只是交换台词。致谢理查德·史密斯
谢谢皮奥特·P·卡瓦斯对于另一种解决方案,它可能有助于脚本 100% 兼容的人自行处理干净的 URL。
location / {
# Size zero static files are served.
# I don't believe that is an issue.
try_files $uri /index.php$request_uri;
}
# If no other .php files are accessible a prefix location of '/index.php/'
# is safer.
location /index.php/ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
# Probably duplicates the contents of fastcgi-php.conf
# fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# include fastcgi_params;
}
只要您的脚本 100% 可以使用干净的 URL,上述解决方案就是可行的方法。在这里,您不需要放置 100 个重写位置块,nginx 会将整个请求 URI 附加到 /index.php,这非常有趣且有用,可能这是真正的解决方案,但就我而言,我的脚本与此并不 100% 兼容。但这仍然是一个很好的、聪明的解决方案。
防止文件夹、文件访问的解决方案
location ~ ^/(data|img)/ {
# Only one is required
deny all;
# return 404;
}
致谢皮奥特·P·卡瓦斯指出,deny all
被某些东西覆盖,在清理服务器块后,它确实解决了这个问题。另外,请确保使用或deny all;
,return 404;
但不要一起使用。