讓 Drupal 或 Apache 在 404 上嘗試代理
我有一個舊版(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,將不會獲得這些樣式或行為
在我看來,我有三個選擇:
- 從 Tomcat 伺服器上複製 css 和 js 文件,並將它們放在 Drupal 根目錄中,同時複製舊的目錄層次結構。這可能有效,但會很混亂,使 Drupal 核心更新復雜化,並且可能會干擾正在工作的內容代理 404 行為的行為。
- 讓 Drupal 為 .js 和 .css 文件觸發 404,就像對 .jsp 文件一樣。任何想法為什麼它還沒有?
- 如果 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]