Last active
September 29, 2021 06:22
-
-
Save 5SMNOONMS5/1d7c54fe0f806b1f90e5d699c914c97c to your computer and use it in GitHub Desktop.
CacheMiddleware for laravel version 7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Http\Middleware; | |
use Closure; | |
use Illuminate\Support\Str; | |
use Illuminate\Http\Request; | |
use Illuminate\Http\Response; | |
// @TIP: Import your CacheService depends on your namespace | |
use App\Service\Cache\CacheService; | |
final class Cache | |
{ | |
/** | |
* Handle an incoming request. | |
* | |
* @param Request $request | |
* @param Closure $next | |
* | |
* @param mixed $tags | |
* | |
* @return mixed | |
*/ | |
public function handle($request, Closure $next, $tags = 'some tags') | |
{ | |
/* | |
不是 GET 跟 HEAD 都略過 | |
來源根據 HTTP 1.1 RFC 2616 S. 9.1 | |
https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1 | |
*/ | |
if (!$request->isMethodCacheable()) { | |
return $next($request); | |
} | |
/* | |
Get Http eTag,這邊會去抓 if_none_match 的 header | |
eTag 可以多值,所以回傳 array | |
根據來源 | |
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag#directives | |
*/ | |
$eTags = $request->getETags(); | |
/* | |
這邊會關係到兩個新的概念 Weak validation ( 弱驗證 )跟 Strong validation ( 強驗證 ) | |
Weak validation 會長這樣 | |
W/"hash-value" | |
Strong validation 會長這樣 | |
"hash-value" | |
大致邏輯就是 | |
一個人去銀行,今天穿紅色衣服,明天他又去銀行,穿了藍色 | |
Weak validation 下,他是同位 | |
Strong validation 是不同位,因為衣服不一樣 | |
假如因為某些原因 (註1) 導致我收到 W/"hash-value" 我希望他跟 "hash-value" 是同樣,就會把 w/ 拿掉 | |
```(註1)```` | |
原因情境我也尚未遇到,以下是我找到的資料 | |
if nginx dynamically gzip your content, it it will convert your ETags into weak ones. | |
來源 https://stackoverflow.com/questions/51973120/where-does-the-w-in-an-etag-appear-from | |
*/ | |
$eTags = array_map([$this, 'stripWeakTags'], $eTags); | |
// Redis tags | |
$tags = is_array($tags) ? $tags : [$tags]; | |
// 如果 match 到任何一個 key 就回傳 | |
foreach ($eTags as $eTag) { | |
if (CacheService::has($tags, $eTag)) { | |
$options[ 'etag' ] = $eTag; | |
return ( new Response() ) | |
->setStatusCode(304) | |
->setCache($options); | |
} | |
} | |
// Get response & content | |
$response = $next($request); | |
$content = $response->getContent(); | |
// 產生 eTag 並且前後加上 雙引號 " | |
$eTag = md5($content); | |
$eTag = Str::of($eTag)->start('"')->finish('"'); | |
// Set etag | |
$options[ 'etag' ] = $eTag; | |
$response->setCache($options); | |
// Set public | |
$response->setPublic(); | |
// Set max-age | |
$response->setMaxAge(0); | |
// Put into redis | |
CacheService::put($tags, $eTag, $content, env('CACHE_TTL')); | |
return $response; | |
} | |
/** | |
* @param $etag | |
* | |
* @return string|string[] | |
*/ | |
private function stripWeakTags($etag) | |
{ | |
return str_replace('W/', '', $etag); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment