Dot-Htaccess

如何在不破壞源文件的相對路徑載入的情況下重寫規則?

  • March 30, 2020

我在伺服器上有一個醜陋的文件系統路徑:example.com/a/b/c/d/e/f/main.html. 為簡單起見,我將example.com/httpdocs/main.html在這個問題的正文中使用。

我希望使用者看到的是example.com/easy-to-remember. 我將example.com/abc在這個問題中使用。

由於問題範圍之外的原因,我想只使用.htaccess文件而不是 php-routing。

讓我們從有效的案例開始:

RewriteEngine On

# Rewrite abc/ directory for loading of source material
   # Rewrite only if there is no actual file or directory that matches this request
   #   This can especially be useful for loading resources  
   #   because then the full paths won't be redirected if they are correct.
   # Note that RewriteRule never sees leading slashes
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteCond %{REQUEST_FILENAME} !-d
   RewriteRule ^abc/(.*)$ httpdocs/$1 [NC,L]

這樣,使用者可以打開example.com/abc/main.html(表達路徑)並顯示內部儲存在example.com/httpdocs/main.html(醜陋路徑)的頁面。使用者永遠看不到內部路徑;url 保留/abc/main.html在他們的瀏覽器中。

到目前為止,一切都按預期工作。在相對路徑中指定的 CSS 源文件main.html仍然可以正確載入。

但也許main.html是一個非常無用的名字。我寧願有example.com/abc一個連結,而不是example.com/abc/main.html. 這將更具表現力,並且允許在不更改連結的情況下對文件副檔名進行內部更改。

# Rewrite abc without trailing slash to main.html
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteCond %{REQUEST_FILENAME} !-d
   RewriteRule ^abc$ httpdocs/main.html
   # PROBLEM: This turns the current url into "example.com/abc", so "./libs"
   # is now looked for in "example.com/libs" instead of "example.com/httpdocs/libs"  

此規則仍然適用於載入main.html而不在 url 中向使用者顯示該名稱。

但是現在錯誤地解析了相對路徑

/httpdocs/main.html依靠/httpdocs/libs/source.css. 在第一種情況下,我們訪問/abc/main.html的地方,源是從中載入的/abc/libs/source.css,這些載入被重定向到,/httpdocs/libs/source.css所以一切正常。在我們訪問/abc的第二種情況下,css 是從載入的/libs/source.css,省略了/httpdocs目錄 - 這會導致 404,因此頁面現在不再正確呈現(以這種方式訪問時)。

顯而易見的解決方案是保留第一種情況,如果我真的不想向main.html使用者顯示名稱,我還可以添加一個重定向/abc/expressive-name/abc/main.html(或直接到/httpdocs/main.html)的規則。

但我很好奇是否有辦法在不向 url 添加第二個深度級別(另一個斜線)的情況下實現我想要做的事情。

我想保持源的載入是相對的,這樣如果我不得不將整個文件系統移動到另一個子域左右,我可以將整個內容複製過來。如果沒有這種限制,我可以簡單地將所有負載設為絕對負載。

如您所見,您必須將主文件的 URL 保持在同一級別,以使相關連結正常工作。一種簡單的方法是使用 URL/abc/而不是/abc.

不同之處在於瀏覽器將其視為目前目錄或基本 URL。基本 URL 是在最後一個 . 之後刪除所有內容的 URL /。因此,/abc基本 URL 是/,而/abc/基本 URL 是/abc.

所以你可以寫:

RewriteRule ^abc/$ httpdocs/main.html

或者你可以省略 URL 中的文件名,如果你提供它

#RewriteCond %{REQUEST_FILENAME} !-f
#RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^abc(.*)$ httpdocs$1
DirectoryIndex main.html

RewriteCond 規則只是為了確保目標不是現有文件或目錄。如您所知,目標不存在,您可以省略規則。

如果您的主文件始終命名為 main.html,您可以DirectoryIndex只添加到根目錄(或共同祖先)。它會使 RewriteRules 更短,因為您不需要為目錄和主文件單獨的 RewriteRules。

一個 get 請求/abc需要一個外部重定向到/abc/,但是如果 apache 檢測到這/abc是一個目錄,它會自動這樣做。

外部重定向的一個有用工具是程序 wget,它可以顯示伺服器發送的重定向。

引用自:https://serverfault.com/questions/922959