Назад | Перейти на главную страницу

Принудительное кэширование вывода обработчика, который активно сопротивляется кешированию

Я пытаюсь принудительно кэшировать очень неприятный фрагмент PHP-скрипта, который без всяких на то оснований активно пытается сопротивляться кешированию, активно устанавливая все заголовки анти-кеша:

Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Content-Type:  text/html; charset=UTF-8
Date:          Thu, 22 May 2014 08:43:53 GMT
Expires:       Thu, 19 Nov 1981 08:52:00 GMT
Last-Modified: 
Pragma:        no-cache
Set-Cookie:    ECSESSID=...; path=/
Vary:          User-Agent,Accept-Encoding
Server:        Apache/2.4.6 (Ubuntu)
X-Powered-By:  PHP/5.5.3-1ubuntu2.3

Если это вообще можно избежать, я вообще не хочу изменять этот сторонний фрагмент кода, а вместо этого просто заставлю Apache на время кэшировать страницу. Я делаю это очень выборочно только для очень определенных страниц, которые не имеют реального влияния на файлы cookie сеанса и т.п., т.е. которые не содержат никакой персонализированной информации.

CacheDefaultExpire      600
CacheMinExpire          600
CacheMaxExpire          1800
CacheHeader             On
CacheDetailHeader       On
CacheIgnoreHeaders      Set-Cookie
CacheIgnoreCacheControl On
CacheIgnoreNoLastMod    On
CacheStoreExpired       On
CacheStoreNoStore       On
CacheLock               On

CacheEnable disk /the/script.php

Apache - это кеширование страница в порядке:

[cache:debug] AH00698: cache: Key for entity /the/script.php?(null) is http://example.com:80/the/script.php?
[cache_disk:debug] AH00709: Recalled cached URL info header http://example.com:80/the/script.php?
[cache_disk:debug] AH00720: Recalled headers for URL http://example.com:80/the/script.php?
[cache:debug] AH00695: Cached response for /the/script.php isn't fresh. Adding conditional request headers.
[cache:debug] AH00750: Adding CACHE_SAVE filter for /the/script.php
[cache:debug] AH00751: Adding CACHE_REMOVE_URL filter for /the/script.php
[cache:debug] AH00769: cache: Caching url: /the/script.php
[cache:debug] AH00770: cache: Removing CACHE_REMOVE_URL filter.
[cache_disk:debug] AH00737: commit_entity: Headers and body for URL http://example.com:80/the/script.php? cached.

Однако он всегда настаивает на том, что «кешированный ответ не свежий» и никогда не обслуживает кешированную версию. я угадать это связано с Expires заголовок, который отмечает документ как просроченный (но я не знаю, правильное ли это предположение). Я пытался перезаписать и сбросить заголовки с помощью mod_headers, но это не помогает; какую бы комбинацию я ни пробовал, кеш совершенно не впечатлил. Я предполагаю, что порядок работы неправильный, и заголовки переписываются после кеш их видит. early обработка заголовка тоже не помогает. Я экспериментировал с CacheQuickHandler Off и пытаюсь установить явные цепочки фильтров, но ничего не помогает. Но я действительно в основном ковыряюсь в темноте, так как у меня нет большого опыта настройки цепочек фильтров Apache.

Есть ли простое решение, как кэшировать этот неприятный фрагмент кода?

Пустой заголовок Last-Modified: делает запрос некэшируемым. Итак, первое, что нужно сделать, это создать его, одно из решений - использовать php auto_prepend_file:

Создать файл prepend.php с таким содержанием:

  <?php header("Last-Modified:" . gmdate("D, d M Y H:i:s"), " GMT"); ?>

Затем добавьте в свою конфигурацию vhost директиву: php_value auto_prepend_file path_to_prepend.php

На этом этапе вы должны убедиться, что ответ сервера имеет правильный Last-Modified: заголовок. В противном случае мы не сможем его кешировать, если да, может ваша работа с mod_headers и mod_cache теперь работает?

Если нет, вы можете использовать squid и apache следующим образом:

Конфигурация Apache

В вашем правильном vhost просто включите mod_rewrite и используйте его для перенаправления трафика, который вы хотите кэшировать:

<VirtualHost your_current_virtual_host:80>
 ServerName your.site.com
 ..
 RewriteEngine on

 # This enables the caching server to see the request  as http://your.site.com/..
 ProxyPreserveHost on

 # This should be at VirtualHost level, not <Directory> or .htaccess


 # The DoSquid env variable decides if we send the request to the cache server
 # Adjust it for your needs
 RewriteRule /the/script.php - [E=DoSquid:Yes]

 # POSTs are not cacheable
 RewriteCond %{REQUEST_METHOD} ^POST$ 
 RewriteRule .* - [E:DoSquid:No]

 # Feel free to add any rule which makes sense for your needs

 # Requests from localhost are calls from the "primary" vhost ( see below )
 RewriteCond %{REMOTE_ADDR} ^127\.0\.0\.1$ [E:DoSquid:No]

 RewriteCond %{ENV:DoSquid} ^Yes$
 RewriteRule /the/script.php http://ip_of_caching_server/this/script.php [P,L,QSA]

 ..
 ..
<VirtualHost/>

# This VirtualHost will be accessed by your caching server as the primary server for your site
# Port 8009 can be anything, it just must be a separate virtual host

<VirtualHost your_current_virtual_host:8009>
 ServerName your.site.com
 ..
 RewriteEngine on

 # Here a make a massive usage of mod_headers in order to have a cacheable response
 # Needless to say, this might completely break your application. The responses are
 # Completely anonymized

 Header unset Set-Cookie
 Header unset Etag
 Header unset Pragma
 RequestHeader unset Cookie

 # Now fix the Cache-Control header..
 Header merge Cache-Control public
 # The max-age is a pain. We have to set one if it's not set, and we have to change it if it's 0
 Header merge Cache-Control "max-age=bidon"
 # Case when we have: Cache-Control max-age=.., ....
 Header edit  Cache-Control "^(.*)max-age=(.*)max-age=bidon, (.*)$" $1max-age=$2$3
 # Case when we have: Cache-Control yyy=bidon, max-age=.."
 Header edit  Cache-Control "^(.*)max-age=(.*), max-age=bidon$" $1max-age=$2
 # Now Replace the value if there was not a max-age, set to 10mn
 Header edit  Cache-Control "max-age=bidon" "max-age=600"
 # Now Replace the value if there was a max-age=0, set to 10mn
 Header edit  Cache-Control "max-age=0" "max-age=600"

 # Remove Cache-Control parameters which prevent caching
 Header edit Cache-Control "no-cache, " ""
 Header edit Cache-Control "no-store, " ""
 Header edit Cache-Control "post-check=0, " ""
 Header edit Cache-Control "pre-check=0, " ""
 Header edit Cache-Control "must-revalidate, " ""

 # The request is now forwarded to the first vhost. It will not loop because we do not cache requests from 127.0.0.1
 ProxyPreserveHost on
 RewriteRule ^(.*)$ http://127.0.0.1/$1 [P,L,QSA]

 ..
 ..
<VirtualHost/>

Конфигурация кэш-сервера

Наверное, можно использовать что угодно: кальмар, апач, лак. с помощью squid вы должны настроить его как обратный прокси и объявить cache_peer your.site.com parent 8009 0 no-query originserver .. Может быть, вы можете просто включить mod_cache во втором vhost добиться желаемого.