如何Nginx重寫以獲得乾淨的頁碼url

如何Nginx重寫以獲得乾淨的頁碼url

最近我們從 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/user/ABC/page/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;
}

它確實會阻止對資料夾的訪問,但是,如果您指定文件名,它仍然會提供服務,而不會拒絕訪問;

apache .htaccess 下的 /data/backup_01012020.zip,僅允許某些使用者在登入時存取此檔案。在它之外,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多變的。如果您也需要查詢參數,您可以使用$request_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;但不能一起使用。

相關內容