2013-05-03 82 views
2

在一個應用程序中,出於歷史原因,某些公共圖像資源被鏈接到替代名稱。例如,我們可能有基於符號鏈接的Apache重定向

a.png 
b.png -> a.png 

谷歌的洞察的PageSpeed從一個統一的網址適用於資產這樣的,以及內容相同的內容,應服。我不希望重組我們已有的資產,而是想讓Apache執行從b.png到a.png的外部重定向。

隨着mod_rewrite的,我可以做的RewriteCond縮小的符號鏈接:

「-l」(是符號鏈接) 將TestString視爲一個路徑名並測試它是否存在,並且是一個符號鏈接。

但是我怎樣才能得到符號鏈接的擴展路徑?我需要它來部分確保目標位於Web範圍內,部分用於執行重定向。

回答

3

(先到這裏後)

我一直在尋找一個解決類似的問題。這是可能的,但沒有簡單的答案。我不得不混合來自多個Google搜索的信息才能使其工作。

首先,關於符號鏈接(維基)注:

的符號鏈接文件系統自動解決。任何 軟件程序在訪問符號鏈接時都會看到目標 ,而不是程序是否知道符號鏈接。

所以,除非開發者阿帕奇添加特定的選項來處理符號鏈接(如你mentionned的-l),我們不得不依靠其他的意思是妥善解決這些問題。

mod_rewriteRewriteMap配置選項。有了它,您可以使用不同類型的外部資源來執行重寫,例如文本文件或數據庫查詢。它也可以調用外部程序,例如...符號鏈接解析器,例如:)

所以,我們走吧。以root身份運行以下所有命令並適應您的系統設置(這是針對Debian的)。


首先,如果我們使用 RewriteMap選項,我們還需要 RewriteLock選項來防止競爭條件。 RewriteLock選項不能位於 <VirtualHost><Directory>上下文中。它必須位於全球範圍內,因此我將其添加到新的 rewrite.conf中並重新加載模塊。 運行以下命令:

lock=/var/lock/apache2/rewrite_lock 
touch $lock 
chown www-data:www-data $lock 
echo "RewriteLock $lock" >> /etc/apache2/mods-available/rewrite.conf 
a2dismod rewrite 
a2enmod rewrite 

接下來,創建/usr/local/bin/resolve-symlink並添加以下代碼:

#!/bin/sh 
while read line 
do 
    echo `readlink "$line"` 
done 

使其可執行文件並進行測試,例如Apache:

chmod +x /usr/local/bin/resolve-symlink 
su - www-data 
/usr/local/bin/resolve-symlink 

腳本應該等待您的輸入,然後返回空白行或給定符號鏈接的目標。使用CTRL+C退出。實施例(>是STDIN,<是STDOUT):

> test 
< 
> /bin/sh 
< bash 
> /bin/bash 
< 

test不存在,所以返回一個空行。 /bin/sh是一個符號鏈接,腳本將其解析爲bash。最後,/bin/bash是一個文件而不是鏈接,因此是另一個空行。

現在,在<VirtualHost>配置,加上下面幾行:

RewriteEngine On 
RewriteMap symlink prg:/usr/local/bin/resolve-symlink 
RewriteLog /var/log/apache2/rewrite.log 
RewriteLogLevel 9 

RewriteMap不能在<Directory>背景下,並不會被激活,除非RewriteEngine也是在<VirtualHost>設置爲on上下文,即使您稍後在<Directory>比賽中將其設置爲on !!!注意所有這些特性並仔細閱讀您的日誌文件,否則您可能會失去幾個小時將您的頭撞到牆上,想知道爲什麼它會顯示「地圖查找失敗」。

最後,重寫,在任何環境下,你更喜歡:

RewriteCond %{REQUEST_FILENAME} -l 
RewriteCond ${symlink:%{REQUEST_FILENAME}} ^(.+)$ 
RewriteRule $ ${REQUEST_SCHEME}://${HTTP_HOST}/%1 [R,L] 

第一線檢測符號鏈接,第二個執行該決議,並檢查結果不是空的,第三行重寫URL(%1是映射的結果),並向瀏覽器發送302重定向。您可能需要END標誌而不是L標誌。

現在重啓apache ......

service apache2 restart 

...測試,檢查你的日誌文件,調整,沖洗和重複...

當您完成後,不要忘記刪除RewriteLogRewriteLogLevel指令從你的配置,因爲他們緩慢阿帕奇下了很多。


重要注意事項。就我而言,符號鏈接都指向同一文件夾內的文件,因此URL重寫更容易一些。如果符號鏈接指向子目錄,或者甚至指向文件系統的其他位置,則必須修改腳本和配置以說明它,但即使如此,它也可能無法按預期工作,因爲apache並不總能夠找出發送給瀏覽器的正確URL。舉例來說,如果你有一個符號鏈接,讓說, /usr/share/apache2/icons/apache_pb.png,阿帕奇可能會重定向至 http://example.com/usr/share/apache2/icons/apache_pb.png其中,當然,不存在...

而且,我會添加一些信息的鏈接,但我很有限到2 ...無論如何,快樂的調試!

+0

帶外部shell腳本的'RewriteMap'是關鍵。謝謝! – crishoj 2014-01-09 20:43:07

+0

嘿!我再次:) 我已經得到了關於這個問題的更多信息。它已經運行了很長一段時間,我做了以下修改: – Cassis 2014-09-28 21:58:40

0

我已經得到了關於這個話題的更多信息。它已經運行了我的身邊一段時間,我做了以下修訂文件/usr/local/bin/resolve-symlinks

#!/bin/bash 

BASE=_ALL_YOUR_BASE_ARE_BELONG_TO_US_ 
BASE_LEN=${#BASE} 

while read FILE 
do 
    # $FILE must be in $BASE 
    if [[ $BASE != ${FILE:0:$BASE_LEN} ]] 
    then 
      echo 
      continue 
    fi 
    REL_FILE=${FILE:$BASE_LEN} 
#  echo $REL_FILE 

    # $LINK must also be in $BASE 
    LINK=$(readlink -f $FILE) 
    if [[ $BASE != ${LINK:0:$BASE_LEN} ]] 
    then 
      echo 
      continue 
    fi 
    REL_LINK=${LINK:$BASE_LEN} 
#  echo $REL_LINK 

    # $REL_FILE and $REL_LINK must be different 
    if [[ $(basename $REL_FILE) == $(basename $REL_LINK) ]] 
    then 
      echo 
      continue; 
    fi 

    # success! 
    echo $REL_LINK 
done 

當然,用你喜歡的路徑替換_ALL_YOUR_BASE_ARE_BELONG_TO_US_。 現在應該確保請求的文件和鏈接目標都在同一個目錄中。