Apache-2.2

讓 Drupal 或 Apache 在 404 上嘗試代理

  • October 1, 2013

我有一個舊版(Tomcat)站點,它曾經被稱為 host.domain,最近部署了一個 Drupal 站點。新的 Drupal 伺服器現在是 host.domain,舊的 Tomcat 伺服器是 legacy.domain。大多數層次結構已在 Drupal 中複製,因此書籤和搜尋引擎結果應該仍然有效:請求 host.domain/dir/page.jsp 並且 Drupal 將修剪 .jsp 並查找名為 dir/page 的節點。一些內容尚未遷移,因此我使用“重定向 404”Drupal 模組在返回 404 之前檢查舊伺服器的內容:請求 host.domain/legacy/oldpage.jsp,Drupal 尋找舊版/oldpage 節點,沒有找到,嘗試 legacy.domain/legacy/oldpage.jsp,找到它,然後使用 drupal_http_request() 透明地將內容傳遞給瀏覽器 - 客戶端的 URL 甚至沒有改變。

問題是 .js 和 .css 文件——出於某種原因,對 host.domain/legacy/file.js 或 file.css 的請求不會觸發 Drupal 的 404 處理,因此 Drupal 從不詢問 legacy.domain 是否有文件. 而是 404 落入 Apache,並顯示 Apache 404(不是 Drupal 或 Tomcat 的)。這意味著通過 Drupal 在 host.domain 上提供的 legacy.domain 上的內容,如果它包含本地 css 或 js,將不會獲得這些樣式或行為

在我看來,我有三個選擇:

  1. 從 Tomcat 伺服器上複製 css 和 js 文件,並將它們放在 Drupal 根目錄中,同時複製舊的目錄層次結構。這可能有效,但會很混亂,使 Drupal 核心更新復雜化,並且可能會干擾正在工作的內容代理 404 行為的行為。
  2. 讓 Drupal 為 .js 和 .css 文件觸發 404,就像對 .jsp 文件一樣。任何想法為什麼它還沒有?
  3. 如果 Drupal 不會為 .js 和 .css 文件拋出 404,那麼告訴 Apache 作為 Drupal 代理行為的第二層。如果 404 出現在 Apache 中,請讓它嘗試從 legacy.domain 提供服務。

我想我也可以瀏覽舊 Tomcat 伺服器上的所有內容,並使用 legacy.domain 名稱將所有相關包含替換為絕對值,但我已經在嘗試將該內容移出該主機,但我真的沒有不想把精力放在即將被替換的文件上——我只是希望它們能夠正常工作,直到我可以遷移它們。有人對實施選項 2 或 3 有任何建議或教程嗎?

Apache 配置是庫存的 Ubuntu 12.04.3 LTS。Drupal 目錄中的 .htaccess 是:

# Protect files and directories from prying eyes.                                           
<FilesMatch "\.(engine|inc|info|install|make|module|profile|test|po|sh|.*sql|theme|tpl(\.php
)?|xtmpl)(~|\.sw[op]|\.bak|\.orig|\.save)?$|^(\..*|Entries.*|Repository|Root|Tag|Template)$|
^#.*#$|\.php(~|\.sw[op]|\.bak|\.orig\.save)$">                                              
 Order allow,deny                                                                          
</FilesMatch>                                                                               

# Don't show directory listings for URLs which map to a directory.                          
Options -Indexes                                                                            

# Follow symbolic links in this directory.                                                  
Options +FollowSymLinks                                                                     

# Make Drupal handle any 404 errors.                                                        
ErrorDocument 404 /index.php                                                                

# Set the default handler.                                                                  
DirectoryIndex index.php index.html index.htm                                               

# Override PHP settings that cannot be changed at runtime. See                              
# sites/default/default.settings.php and drupal_environment_initialize() in
# includes/bootstrap.inc for settings that can be changed at runtime.

# PHP 5, Apache 1 and 2.
<IfModule mod_php5.c>
 php_flag magic_quotes_gpc                 off
 php_flag magic_quotes_sybase              off
 php_flag register_globals                 off
 php_flag session.auto_start               off
 php_value mbstring.http_input             pass
 php_value mbstring.http_output            pass
 php_flag mbstring.encoding_translation    off
</IfModule>

# Requires mod_expires to be enabled.
<IfModule mod_expires.c>
 # Enable expirations.
 ExpiresActive On

 # Cache all files for 2 weeks after access (A).
 ExpiresDefault A1209600

 <FilesMatch \.php$>
   # Do not allow PHP scripts to be cached unless they explicitly send cache
   # headers themselves. Otherwise all scripts would have to overwrite the
   # headers set by mod_expires if they want another caching behavior. This may
   # fail if an error occurs early in the bootstrap process, and it may cause
   # problems if a non-Drupal PHP file is installed in a subdirectory.
   ExpiresActive Off
 </FilesMatch>
</IfModule>

# Various rewrite rules.
<IfModule mod_rewrite.c>
 RewriteEngine on

# This forces all drupal links to end in a trailing slash.
# Companion rules to trailing slash module.
# https://drupal.org/project/trailing_slash
RewriteBase /
RewriteCond %{REQUEST_METHOD} !=post [NC]
RewriteRule ^(.*(?:^|/)[^/\.]+)$ $1/ [L,R=301]

 # Set "protossl" to "s" if we were accessed via https://.  This is used later
 # if you enable "www." stripping or enforcement, in order to ensure that
 # you don't bounce between http and https.
 RewriteRule ^ - [E=protossl]
 RewriteCond %{HTTPS} on
 RewriteRule ^ - [E=protossl:s]

 # Make sure Authorization HTTP header is available to PHP
 # even when running as CGI or FastCGI.
 RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

 # Block access to "hidden" directories whose names begin with a period.
 RewriteRule "(^|/)\." - [F]

 # Pass all requests not referring directly to files in the filesystem to
 # index.php. Clean URLs are handled in drupal_environment_initialize().
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteCond %{REQUEST_FILENAME} !-d
 RewriteCond %{REQUEST_URI} !=/favicon.ico
 RewriteRule ^ index.php [L]

 # Rules to correctly serve gzip compressed CSS and JS files.
 # Requires both mod_rewrite and mod_headers to be enabled.
 <IfModule mod_headers.c>
   # Serve gzip compressed CSS files if they exist and the client accepts gzip.
   RewriteCond %{HTTP:Accept-encoding} gzip
   RewriteCond %{REQUEST_FILENAME}\.gz -s
   RewriteRule ^(.*)\.css $1\.css\.gz [QSA]

   # Serve gzip compressed JS files if they exist and the client accepts gzip.
   RewriteCond %{HTTP:Accept-encoding} gzip
   RewriteCond %{REQUEST_FILENAME}\.gz -s
   RewriteRule ^(.*)\.js $1\.js\.gz [QSA]

   # Serve correct content types, and prevent mod_deflate double gzip.
   RewriteRule \.css\.gz$ - [T=text/css,E=no-gzip:1]
   RewriteRule \.js\.gz$ - [T=text/javascript,E=no-gzip:1]

   <FilesMatch "(\.js\.gz|\.css\.gz)$">
     # Serve correct encoding type.
     Header set Content-Encoding gzip
     # Force proxies to cache gzipped & non-gzipped css/js files separately.
     Header append Vary Accept-Encoding
   </FilesMatch>
 </IfModule>
</IfModule>

更新

根據下面 Shane Madden 的建議,我已將此添加到根 .htaccess 的 mod_rewrite 部分的頂部:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} \.(css|js)$
RewriteRule ^(.*)$ http://legacy.domain/$1 [L]

如果我要求提供 host.domain/oldfile.css,則此方法有效:即使舊主機上不存在 oldfile.css,我也會得到 Tomcat 404,因此我知道重寫有效。問題在於不存在的目錄中不存在的目錄。

如果我在舊系統上有一個文件:

http://legacy.domain/root.css

並在

http://host.domain/root.css

該文件將顯示出來,因為它符合三個 RewriteCond 規則。但是,如果我要求

http://host.domain/long/path/to/file.css

然後我得到一個 Apache(不是 Tomcat)404,在 error.log 中有一個條目:

File does not exist: /var/www/long

看起來重寫規則僅在請求的文件與包含該規則的 .htaccess 位於(或將)在同一目錄中時才生效。如果請求的文件在目錄中,則該目錄會觸發 404,這與條件不匹配,因為它不以 .css 或 .js 結尾,並且 Apache 會在此處停止處理。有沒有辦法讓規則適用於任何404,無論它在本地不存在的目錄層次結構中有多遠?

直接代理文件系統上不存在的 css 和 js 文件怎麼樣,因為 drupal 站點的文件都應該訪問/sites目錄中的真實文件?

<Directory>您的 Drupal 安裝塊中,如下所示:

RewriteCond %{REQUEST_FILENAME} \.(css|js)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ http://proxy-target/$1 [P,L]

編輯:

由於文件系統映射在檢查是否存在之前就阻塞了,所以讓我們在不需要文件系統映射的情況下進行檢查。

將其直接放入您的<VirtualHost>塊中(如果您不使用虛擬主機,則將其放入主伺服器配置中):

RewriteCond %{REQUEST_URI} \.(css|js)$
RewriteCond /path/to/your/docroot%{REQUEST_URI} !-f
RewriteRule ^/(.*)$ http://proxy-target/$1 [P,L]

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