1

我们目前正在运行一个使用 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);

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

4

3 回答 3

2

从进一步的实验来看,问题不在于导致 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;
    }
}
于 2012-04-26T14:46:32.080 回答
0

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

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

于 2013-04-12T09:17:08.330 回答
-1

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

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

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

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

于 2012-04-19T17:58:49.243 回答