如何在 Silverstripe 控制器中缓存 JSON 响应?
How to cache a JSON response in the Silverstripe Controller?
我们有一个 Silverstripe 4 项目,它充当无头 CMS,返回一组格式为 JSON 的复杂数据模型。
代码示例如下:
class APIController extends ContentController
{
public function index(HTTPRequest $request)
{
$dataArray['model1'] = AccessPointController::getModel1();
$dataArray['model2'] = AccessPointController::getModel2();
$dataArray['model3'] = AccessPointController::getModel3();
$dataArray['model4'] = AccessPointController::getModel4();
$dataArray['model5'] = AccessPointController::getModel5();
$dataArray['model6'] = AccessPointController::getModel6();
$this->response->addHeader('Content-Type', 'application/json');
$this->response->addHeader('Access-Control-Allow-Origin', '*');
return json_encode($dataArray);
}
我们遇到的问题是数据模型变得如此复杂,JSON 的生成时间是 运行 秒。
JSON 只应在网站内容更新时更改,因此理想情况下我们希望缓存 JSON & 而不是为每次调用动态生成它。
缓存上述示例中的 JSON 的最佳方法是什么?
你看过the silverstripe docs about caching了吗?
它们确实提供了一种将内容存储在缓存中的编程方式。以及配置选项是什么后端用于存储缓存。
一个简单的例子可能是:
我在这里延长了缓存的生存时间,但您仍然应该注意,这个缓存并不是为了存储生成的静态内容,而是为了减少负载。您的应用程序仍然必须每 86400 秒(24 小时)计算一次 api 响应。
# app/_config/apiCache.yml
---
Name: apicacheconfig
---
# [... rest of your config config ...]
SilverStripe\Core\Injector\Injector:
Psr\SimpleCache\CacheInterface.apiResponseCache:
factory: SilverStripe\Core\Cache\CacheFactory
constructor:
namespace: "apiResponseCache"
defaultLifetime: 86400
<?php // app/src/FooController.php
class FooController extends \SilverStripe\Control\Controller {
public function getCache() {
return Injector::inst()->get('Psr\SimpleCache\CacheInterface.apiResponseCache');
// or your own cache (see below):
// return new MyCache();
}
protected function hasDataBeenChanged() {
// alternative to this method, you could also simply include Page::get()->max('LastEdited') or whatever in your cache key inside index(), but if you are using your own cache system, you need to handle deleting of old unused cache files. If you are using SilverStripe's cache, it will do that for you
$c = $this->getCache();
$lastCacheTime = $c->has('cacheTime') ? (int)$c->get('cacheTime') : 0;
$lastDataChangeTime = strtotime(Page::get()->max('LastEdited'));
return $lastDataChangeTime > $lastCacheTime;
}
public function index() {
$c = $this->getCache();
$cacheKey = 'indexActionResponse';
if ($c->has($cacheKey) && !$this->hasDataBeenChanged()) {
$data = $c->get($cacheKey);
} else {
$dataArray['model1'] = AccessPointController::getModel1();
$dataArray['model2'] = AccessPointController::getModel2();
$dataArray['model3'] = AccessPointController::getModel3();
$dataArray['model4'] = AccessPointController::getModel4();
$dataArray['model5'] = AccessPointController::getModel5();
$dataArray['model6'] = AccessPointController::getModel6();
$data = json_encode($dataArray);
$c->set($cacheKey, $data);
$c->set('cacheTime', time());
}
$this->response->addHeader('Content-Type', 'application/json');
$this->response->addHeader('Access-Control-Allow-Origin', '*');
return json_encode($dataArray);
}
}
如果您正在寻找 permanent/persistent 缓存,它只会在数据更改时更新,我建议您寻找不同的后端或自己实现一个简单的缓存并使用它而不是silverstripe 缓存。
class MyCache {
protected function fileName($key) {
if (strpos($key, '/') !== false || strpos($key, '\') !== false) {
throw new \Exception("Invalid cache key '$key'");
}
return BASE_PATH . "/api-cache/$key.json";
}
public function get($key) {
if ($this->has($key)) {
return file_get_contents($this->fileName($key));
}
return null;
}
public function set($key, $val) {
file_put_contents($this->fileName($key), $val);
}
public function has($key) {
$f = $this->fileName($key);
return @file_exists($f);
}
我们有一个 Silverstripe 4 项目,它充当无头 CMS,返回一组格式为 JSON 的复杂数据模型。
代码示例如下:
class APIController extends ContentController
{
public function index(HTTPRequest $request)
{
$dataArray['model1'] = AccessPointController::getModel1();
$dataArray['model2'] = AccessPointController::getModel2();
$dataArray['model3'] = AccessPointController::getModel3();
$dataArray['model4'] = AccessPointController::getModel4();
$dataArray['model5'] = AccessPointController::getModel5();
$dataArray['model6'] = AccessPointController::getModel6();
$this->response->addHeader('Content-Type', 'application/json');
$this->response->addHeader('Access-Control-Allow-Origin', '*');
return json_encode($dataArray);
}
我们遇到的问题是数据模型变得如此复杂,JSON 的生成时间是 运行 秒。
JSON 只应在网站内容更新时更改,因此理想情况下我们希望缓存 JSON & 而不是为每次调用动态生成它。
缓存上述示例中的 JSON 的最佳方法是什么?
你看过the silverstripe docs about caching了吗?
它们确实提供了一种将内容存储在缓存中的编程方式。以及配置选项是什么后端用于存储缓存。
一个简单的例子可能是:
我在这里延长了缓存的生存时间,但您仍然应该注意,这个缓存并不是为了存储生成的静态内容,而是为了减少负载。您的应用程序仍然必须每 86400 秒(24 小时)计算一次 api 响应。
# app/_config/apiCache.yml
---
Name: apicacheconfig
---
# [... rest of your config config ...]
SilverStripe\Core\Injector\Injector:
Psr\SimpleCache\CacheInterface.apiResponseCache:
factory: SilverStripe\Core\Cache\CacheFactory
constructor:
namespace: "apiResponseCache"
defaultLifetime: 86400
<?php // app/src/FooController.php
class FooController extends \SilverStripe\Control\Controller {
public function getCache() {
return Injector::inst()->get('Psr\SimpleCache\CacheInterface.apiResponseCache');
// or your own cache (see below):
// return new MyCache();
}
protected function hasDataBeenChanged() {
// alternative to this method, you could also simply include Page::get()->max('LastEdited') or whatever in your cache key inside index(), but if you are using your own cache system, you need to handle deleting of old unused cache files. If you are using SilverStripe's cache, it will do that for you
$c = $this->getCache();
$lastCacheTime = $c->has('cacheTime') ? (int)$c->get('cacheTime') : 0;
$lastDataChangeTime = strtotime(Page::get()->max('LastEdited'));
return $lastDataChangeTime > $lastCacheTime;
}
public function index() {
$c = $this->getCache();
$cacheKey = 'indexActionResponse';
if ($c->has($cacheKey) && !$this->hasDataBeenChanged()) {
$data = $c->get($cacheKey);
} else {
$dataArray['model1'] = AccessPointController::getModel1();
$dataArray['model2'] = AccessPointController::getModel2();
$dataArray['model3'] = AccessPointController::getModel3();
$dataArray['model4'] = AccessPointController::getModel4();
$dataArray['model5'] = AccessPointController::getModel5();
$dataArray['model6'] = AccessPointController::getModel6();
$data = json_encode($dataArray);
$c->set($cacheKey, $data);
$c->set('cacheTime', time());
}
$this->response->addHeader('Content-Type', 'application/json');
$this->response->addHeader('Access-Control-Allow-Origin', '*');
return json_encode($dataArray);
}
}
如果您正在寻找 permanent/persistent 缓存,它只会在数据更改时更新,我建议您寻找不同的后端或自己实现一个简单的缓存并使用它而不是silverstripe 缓存。
class MyCache {
protected function fileName($key) {
if (strpos($key, '/') !== false || strpos($key, '\') !== false) {
throw new \Exception("Invalid cache key '$key'");
}
return BASE_PATH . "/api-cache/$key.json";
}
public function get($key) {
if ($this->has($key)) {
return file_get_contents($this->fileName($key));
}
return null;
}
public function set($key, $val) {
file_put_contents($this->fileName($key), $val);
}
public function has($key) {
$f = $this->fileName($key);
return @file_exists($f);
}