mikespub / micheh-psr7-cache
PSR-7 HTTP 消息的缓存和条件请求辅助工具
Requires
- php: >=8.1
- psr/http-message: ^1.1 || ^2.0
Requires (Dev)
- phpstan/phpstan: ^1.10
- phpunit/phpunit: ^10.5
README
此库提供了一个简单的方法,既可以向 PSR-7 HTTP 消息实现添加缓存相关的头部,也可以从 PSR-7 消息中提取缓存和条件请求信息(例如,如果响应可缓存)。它还提供了一个 Cache-Control
值对象,用于提供面向对象的接口来操作 Cache-Control
头部。
此分支(PHP 8.1+)的安装
使用 Composer 安装此库
$ composer require mikespub/micheh-psr7-cache
注意:原始包仍然可在 micheh/psr7-cache 获得,但不再维护
快速入门
要启用 HTTP 响应的缓存,创建一个 CacheUtil
实例,调用 withCache
方法并提供您的 PSR-7 响应。
/** @var \Psr\Http\Message\ResponseInterface $response */ $util = new \Micheh\Cache\CacheUtil(); $response = $util->withCache($response);
这将向您的响应添加头部 Cache-Control: private, max-age=600
。具有此头部,响应只由发送请求的客户缓存,并缓存 600 秒(10 分钟)。在这段时间内,客户端应使用缓存中的响应,而无需向应用程序发送新的请求。
缓存验证器
应用程序还应将缓存验证器添加到响应中:一个 ETag
头部(如果您知道资源最后修改的时间,还有一个 Last-Modified
头部)。这样,客户端也会在请求中包含 ETag
和 Last-Modified
信息,应用程序可以检查客户端是否仍然具有当前状态。
/** @var \Psr\Http\Message\ResponseInterface $response */ $util = new \Micheh\Cache\CacheUtil(); $response = $util->withCache($response); $response = $util->withETag($response, 'my-etag'); $response = $util->withLastModified($response, new \DateTime());
重新验证响应
要确定客户端是否仍然具有页面的当前副本且响应未修改,可以使用 isNotModified
方法。只需将缓存头部添加到响应中,然后调用该方法并传递请求和响应。该方法将自动比较请求的 If-None-Match
头部与响应的 ETag
头部(如果可用,请求的 If-Modified-Since
头部与响应的 Last-Modified
头部)。如果响应未修改,则返回带有缓存头部和状态码 304
(未修改)的空响应。这将指示客户端使用之前请求的缓存副本,从而节省 CPU/内存使用和带宽。因此,为了提高性能,在 isNotModified
调用之前,应尽可能保持代码尽可能轻量。不要在此方法之前创建完整的响应。
/** @var \Psr\Http\Message\RequestInterface $request */ /** @var \Psr\Http\Message\ResponseInterface $response */ $util = new \Micheh\Cache\CacheUtil(); $response = $util->withCache($response); $response = $util->withETag($response, 'my-etag'); $response = $util->withLastModified($response, new \DateTime()); if ($util->isNotModified($request, $response)) { return $response->withStatus(304); } // create the body of the response
使用不安全方法的条件请求
虽然上述过程通常是可选的,并且适用于安全方法(GET 和 HEAD),但也可以强制客户端具有当前资源状态。这对于不安全方法(例如 POST、PUT、PATCH 或 DELETE)很有用,因为这可以防止更新丢失(例如,如果另一个客户端在您的请求之前更新了资源)。一个好的做法是,最初使用 hasStateValidator
方法检查请求是否包含适当的头部(对于 ETag
的 If-Match
以及/或对于 Last-Modified
日期的 If-Unmodified-Since
)。如果请求不包含此信息,则中止执行并返回状态码 428
(预处理要求)或如果只想使用原始状态码,则返回状态码 403
(禁止)。
/** @var \Psr\Http\Message\RequestInterface $request */ $util = new \Micheh\Cache\CacheUtil(); if (!$util->hasStateValidator($request)) { return $response->withStatus(428); }
如果请求中包含了状态验证器,您可以使用hasCurrentState
方法来检查请求是否包含当前资源状态,而不是过时的版本。如果请求包含过时的资源状态(另一个ETag
或较旧的Last-Modified
日期),则终止执行并返回状态码412
(预条件失败)。否则,您可以继续处理请求并更新/删除资源。一旦资源被更新,最好在响应中包含更新的ETag
(以及如果有的话,Last-Modified
日期)。
/** @var \Psr\Http\Message\RequestInterface $request */ /** @var \Psr\Http\Message\ResponseInterface $response */ $util = new \Micheh\Cache\CacheUtil(); if (!$util->hasStateValidator($request)) { return $response->withStatus(428); } $eTag = 'my-etag' $lastModified = new \DateTime(); if (!$util->hasCurrentState($request, $eTag, $lastModified)) { return $response->withStatus(412); } // process the request
可用的辅助方法
参考
许可证
本存档中的文件采用BSD-3-Clause许可证。您可以在LICENSE.md中找到此许可证的副本。