【问题标题】:Preventing error pages caching when using Zend_Cache_Backend_Static使用 Zend_Cache_Backend_Static 时防止错误页面缓存
【发布时间】:2012-04-19 12:47:12
【问题描述】:

我们目前正在运行一个使用 Zend_Cache_Backend_Static 将页面缓存到静态 html 文件的应用程序。这非常有效,除了当请求不正确的 url 时,我们的缓存会被数百个空文件和文件夹填满。如果抛出异常,有什么方法可以防止页面被缓存?我惊讶地发现这不是标准行为。

我做了一些挖掘,实际处理保存静态 html 页面的 ZF 代码如下在 Zend_Cache_Frontend_Capture 中:

public function _flush($data) {        
    $id = array_pop($this->_idStack);
    if ($id === null) {
        Zend_Cache::throwException('use of _flush() without a start()');
    }
    if ($this->_extension) {
        $this->save(serialize(array($data, $this->_extension)), $id, $this->_tags);
    } else {
        $this->save($data, $id, $this->_tags);
    }
    return $data;
}

这个函数是 ob_start 的 output_callback。我尝试获取响应对象来测试状态,但它似乎在 _flush 中不起作用。

$response = Zend_Controller_Front::getInstance()->getResponse();

if($response->getStatus() == '200') {
    // do the save as normal
}
else {
    // do nothing
    return false;
}

我唯一的另一个想法是测试 $data 的长度,仅在 strlen($data) > 0 似乎有效但感觉不够健壮时才进行缓存。

更新:

不幸的是,当我们点击 ErrorController 时,静态页面已经写入缓存,因此此时禁用缓存将不起作用。但是,可以根据 $_SERVER['REQUEST_URI'] 删除页面,这是首次写入页面时用作 id 的内容。这行可以添加到ErrorController中errorAction的开始:

$this->_helper->cache->removePage($_SERVER['REQUEST_URI'], true);

它工作得很好,但我不想一开始就写这个页面!

【问题讨论】:

    标签: php zend-framework


    【解决方案1】:

    从进一步的实验来看,问题不在于导致 404 的标准 Zend Framework 异常(即 Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE、Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER、Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION),而是我的自定义异常。现在想想,这真的很明显,因为 Zend_Cache_Backend_Static 需要在动作控制器的 init 方法中初始化。任何没有路由、控制器或动作的情况,它都不会被初始化。

    我在现有操作中抛出异常,用户可能正在查询不存在的文章。因此,在 init 中启用了缓存,并且在我们在 Front Controller Plugin 中点击 postDispatch 时已经写入了页面(仍然不确定为什么会出现这种情况),所以我当时无法取消。一种解决方案是在抛出异常时取消缓存。管理静态页面缓存的标准方法是使用 Zend_Controller_Action_Helper_Cache 动作助手。我已经对此进行了扩展以添加一个取消方法,如下所示:

    <?php
    
    class Zend_Controller_Action_Helper_PageCache extends Zend_Controller_Action_Helper_Cache {
    
        public function cancel() {
            $cache = $this->getCache(Zend_Cache_Manager::PAGECACHE);
            $cache->setOption('caching', false);
            $cache->getBackend('disable_caching', true);
        }
    }
    

    我的动作控制器现在看起来像这样:

    <?php
    
    class IndexController extends Zend_Controller_Action {
    
        private $_model;
    
        public function init() {        
            $this->_model = new Model();
    
            // using extended pageCache rather than $this->_helper->cache:
            $this->_helper->pageCache(array('index'), array('indexaction'));
        }
    
        public function indexAction() {
            $alias = $this->_request->getParam('article');
            $article = $this->_model->getArticleByAlias($alias);
    
            if(!$article) {
                // new cancel method will disable caching
                $this->_helper->pageCache->cancel();
                throw new Zend_Controller_Action_Exception('Invalid article alias', 404);
            }
    
            $this->view->article = $article;
        }
    }
    

    【讨论】:

      【解决方案2】:

      您应该更改您的 .htaccess 文件 RewriteRules 以使用选项 -s 检查文件大小

      这样,如果在缓存页面时发生错误(从而生成 0 字节文件),它将不会永久存储在缓存中。

      【讨论】:

        【解决方案3】:

        如果您使用标准 ErrorController 处理 404、500 和未处理的异常,并且可以从那里获取对缓存对象的引用,则可以从错误处理程序中禁用缓存。

        在您的错误控制器(或您想取消缓存的任​​何地方)中,尝试:

        $cache->setOption('caching', false);
        

        Zend_Cache_Coresave() 方法被Zend_Cache_Frontend_Capture::_flush() 调用时,它会看到caching 选项设置为false,它实际上不会将数据保存到缓存并返回true。

        【讨论】:

        • 当我们点击ErrorController的时候静态页面已经写好了,所以这没有任何效果。
        • 在这种情况下,在routeShutdown() 运行的插件可能会足够早地禁用缓存,但那时您应该知道页面是 404。
        • 令人沮丧的是, routeShutdown() 为时过早。我在我的控制器中抛出自定义异常,我也不想缓存。我尝试过使用 postDespatch,但这又为时已晚!我一直在试图弄清楚为什么为时已晚,但我似乎无法找到触发 ob 刷新以及缓存保存的原因。
        • 我已经给了你接受的答案,因为没有这个我就不会到达那里。我只需要找到正确的禁用位置!
        • 没有看到你之前的评论,很高兴你能找到它。我猜 postDispatch 为时已晚,因为它会在控制器和动作调度之后运行,但由于抛出异常,postDispatch 可能永远不会被调用,或者如果它确实如此,如你所说,为时已晚。也就是说,您可能有更好的运气子类化Zend_Controller_Plugin_ErrorHandler 并用您的子类化版本替换默认的应用程序错误处理程序。这样您就可以完全控制错误处理。
        猜你喜欢
        • 2011-05-07
        • 2020-05-27
        • 1970-01-01
        • 1970-01-01
        • 2013-02-20
        • 2013-05-18
        • 2011-11-04
        • 2014-07-20
        相关资源
        最近更新 更多