Slim4 Middleware is used to cache page requests

  • there is a feature we often use when writing pages or interfaces.
  1. Usually a request comes, we query it from the database, and then return it after the data conversion processing is completed
  2. However, some pages, such as the home page or the data of an interface, are not changed frequently
  3. Therefore, we can cache the contents to a store like ‘Redis’ before the first request processing completes the output
  4. The next time you request this, read the data from ‘Redis’ first, and return it directly without processing.
  5. If the cache expires, repeat [3, 4]
<?php

namespace App\Middleware;


use Nyholm\Psr7\Stream;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

class PageCacheMiddleware
{

    public function __invoke(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $paths = [
            '/' => [],
            '/categories' => [],
            '/articles' => [],
        ];
        $requestPath = $request->getUri()->getPath();
    
        // 不需要缓存的路由
        if (! isset($paths[$requestPath])) {

            return $handler->handle($request);
        }
        
        
        // 可能,你的 cacheKey 还需要加一些参数辨别,例如 page=1
        $requestParameters = $request->getQueryParams();
        $cacheKey = base64_encode($requestPath . json_encode($requestParameters));
        
        // 这里,你可以从缓存中获取,这里为了演示简单,直接通过文件读写来达到缓存的效果
        if (file_exists($cacheKey)) {
            
            list($cacheResponse, $cacheContent) = unserialize(file_get_contents($cacheKey));
            if ($cacheResponse instanceof ResponseInterface) {
                
                $newResponse = $cacheResponse->withBody(Stream::create($cacheContent));
                return $newResponse;
            }
        }
    
        $response = $handler->handle($request);
        
        // 这里,我们把这个 Response 对象缓存起来,因为我们需要响应头等信息,
        // 还缓存了 body,这里最为重要,slim4 的 body 使用 php_temp 流,
        // 而 PHP 中说到,流是不能序列化的。所以我们也缓存一个内容
        file_put_contents($cacheKey, serialize([$response, (string)$response->getBody()]));
        
        return $response;
    }
}
2 Likes

Hi,

Can you show me an real example of this class?

Thank you!

I think there’s a little typo

if (! isset($paths[$requestPath])) {

        return $handler->handle($request);
}

This shoud be

if (isset($paths[$requestPath])) {

        return $handler->handle($request);

}