CheckRequestCache.php 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2019 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types = 1);
  12. namespace think\middleware;
  13. use Closure;
  14. use think\Cache;
  15. use think\Config;
  16. use think\Request;
  17. use think\Response;
  18. /**
  19. * 请求缓存处理
  20. */
  21. class CheckRequestCache
  22. {
  23. /**
  24. * 缓存对象
  25. * @var Cache
  26. */
  27. protected $cache;
  28. /**
  29. * 配置参数
  30. * @var array
  31. */
  32. protected $config = [
  33. // 请求缓存规则 true为自动规则
  34. 'request_cache_key' => true,
  35. // 请求缓存有效期
  36. 'request_cache_expire' => null,
  37. // 全局请求缓存排除规则
  38. 'request_cache_except' => [],
  39. // 请求缓存的Tag
  40. 'request_cache_tag' => '',
  41. ];
  42. public function __construct(Cache $cache, Config $config)
  43. {
  44. $this->cache = $cache;
  45. $this->config = array_merge($this->config, $config->get('route'));
  46. }
  47. /**
  48. * 设置当前地址的请求缓存
  49. * @access public
  50. * @param Request $request
  51. * @param Closure $next
  52. * @param mixed $cache
  53. * @return Response
  54. */
  55. public function handle($request, Closure $next, $cache = null)
  56. {
  57. if ($request->isGet() && false !== $cache) {
  58. $cache = $cache ?: $this->getRequestCache($request);
  59. if ($cache) {
  60. if (is_array($cache)) {
  61. list($key, $expire, $tag) = $cache;
  62. } else {
  63. $key = str_replace('|', '/', $request->url());
  64. $expire = $cache;
  65. $tag = null;
  66. }
  67. if (strtotime($request->server('HTTP_IF_MODIFIED_SINCE', '')) + $expire > $request->server('REQUEST_TIME')) {
  68. // 读取缓存
  69. return Response::create()->code(304);
  70. } elseif (($hit = $this->cache->get($key)) !== null) {
  71. list($content, $header, $when) = $hit;
  72. if ($expire === null || $when + $expire > $request->server('REQUEST_TIME')) {
  73. return Response::create($content)->header($header);
  74. }
  75. }
  76. }
  77. }
  78. $response = $next($request);
  79. if (isset($key) && 200 == $response->getCode() && $response->isAllowCache()) {
  80. $header = $response->getHeader();
  81. $header['Cache-Control'] = 'max-age=' . $expire . ',must-revalidate';
  82. $header['Last-Modified'] = gmdate('D, d M Y H:i:s') . ' GMT';
  83. $header['Expires'] = gmdate('D, d M Y H:i:s', time() + $expire) . ' GMT';
  84. $this->cache->tag($tag)->set($key, [$response->getContent(), $header, time()], $expire);
  85. }
  86. return $response;
  87. }
  88. /**
  89. * 读取当前地址的请求缓存信息
  90. * @access protected
  91. * @param Request $request
  92. * @return mixed
  93. */
  94. protected function getRequestCache($request)
  95. {
  96. $key = $this->config['request_cache_key'];
  97. $expire = $this->config['request_cache_expire'];
  98. $except = $this->config['request_cache_except'];
  99. $tag = $this->config['request_cache_tag'];
  100. if ($key instanceof \Closure) {
  101. $key = call_user_func($key, $request);
  102. }
  103. if (false === $key) {
  104. // 关闭当前缓存
  105. return;
  106. }
  107. foreach ($except as $rule) {
  108. if (0 === stripos($request->url(), $rule)) {
  109. return;
  110. }
  111. }
  112. if (true === $key) {
  113. // 自动缓存功能
  114. $key = '__URL__';
  115. } elseif (strpos($key, '|')) {
  116. list($key, $fun) = explode('|', $key);
  117. }
  118. // 特殊规则替换
  119. if (false !== strpos($key, '__')) {
  120. $key = str_replace(['__CONTROLLER__', '__ACTION__', '__URL__'], [$request->controller(), $request->action(), md5($request->url(true))], $key);
  121. }
  122. if (false !== strpos($key, ':')) {
  123. $param = $request->param();
  124. foreach ($param as $item => $val) {
  125. if (is_string($val) && false !== strpos($key, ':' . $item)) {
  126. $key = str_replace(':' . $item, $val, $key);
  127. }
  128. }
  129. } elseif (strpos($key, ']')) {
  130. if ('[' . $request->ext() . ']' == $key) {
  131. // 缓存某个后缀的请求
  132. $key = md5($request->url());
  133. } else {
  134. return;
  135. }
  136. }
  137. if (isset($fun)) {
  138. $key = $fun($key);
  139. }
  140. return [$key, $expire, $tag];
  141. }
  142. }