无论你的项目是什么(RESTful API、Web 平台等),都可以利用 Laravel 提供的非常有用且直观的缓存机制去响应你的内容。 一般来说,不管你发送什么数据(HTML、JSON、collections、Eloquent 的对象等),Laravel 都会在其过期之前帮你存到缓存系统中。
下面是一个简单的使用缓存的代码段:
return Cache::remember($rememberKey, $minutes , function() use ($data) {
return $data;
});
很容易理解,这上面调用了 remember()
,并且发送 $rememberKey
(标识缓存的名字)以及到期时间(以分钟为单位) 来获取缓存中的数据。而一旦要找的缓存不存在,闭包函数里面的内容就被运行,并将返回的结果以 $rememberKey
为名、$minutes
为到期时间存储在缓存中。你可能会好奇这简短的一行居然实现了这么多步骤,深感 Laravel 之强大之优雅的同时,我们还是赶紧来刨根问底吧。
Laravel 的缓存机制中还有 put()
、 pull()
和 get()
等方法,具体看 文档 就能行了。可是这里一定要隆重地强调一下 remember()
这个方法,这货太好用了,包揽了查询和存储两大我们所需要的基本功能。
那么问题来了:Laravel 要怎么确定何时存储数据?
很简单,这个问题的关键是 $rememberKey
这个值,根据这个值 Laravel 会知道这个数据是否已经被缓存。因为没理由你会干出用同一个 $rememberKey
去作为所有你想缓存的数据的名字吧?(有我也是服了你了)
不过这对于其他场景来说并不是很管用。假设当你知道 $rememberKey
作为唯一值的重要性,你决定使用当前的 URL 作为缓存数据的标识,然后你就写了这样的代码:
$url = request()->url();
return Cache::remember($url, $minutes, function () use ($data) {
return $data;
});
同样的道理,但现在上面的 $rememberKey
是当前请求的 URL,然后你就很得意地确定 $rememberKey
会根据请求而改变(即它不会是一个唯一值)。
例如,如果你收到对 yourdomain.com/products
的请求,然后使用该确切值去查找缓存来响应。 当用户跳转到另一个 URL(如 yourdomain.com/categories
)时,同理只要确保返回缓存中相应的值并且相应地进行存储。
很方便对不?你也是这么做的么?那我该提醒你小心被自己写的坑反咬一口了~
假设你要对查询的结果进行排序或分页,那 URL 就会是这种情况:yourdomain.com/products?page=2&sort_by=price
。当你用 $url = request()->url()
获取当前的 URL 时,它不会获取查询参数(page=2&sort_by=price
),这意味着查询参数引入的数据更改不会被返回出来。
觉得掉坑了?没关系!爬出来就是了!现在问题的关键是我们需要把包含查询参数拿出来就行了,那就换个方法:
$fullUrl = request()->fullUrl();
return Cache::remember($fullUrl, $minutes, function () use ($data) {
return $data;
});
行了,这样就写就 OK 了!不相信?无所谓~有耐心的话,大可测试一下。
访问 yourdomain.com/products?page=2&sort_by=price
,它缓存数据并返回。再访问 yourdomain.com/products?page=1&sort_by=name
,它还是会再次缓存数据并返回。是不是很棒!它缓存不同的响应数据并返回。
可是,现在,我们还得最后再做一次测试。现在先访问 yourdomain.com/products?page=2&sort_by=price
,然后访问 yourdomain.com/products?sort_by=price&page=2
。这是两个不同的 rememberKey
,所以系统会分开缓存。但是啊!这两个请求返回的是同样的数据呀!按照正常人类思维逻辑,查询字符串的顺序并不重要,如果缓存数据里面存储了相同的数据,它应该返回同一个缓存数据,而不是两个 rememberKey
不同内容却相同的数据。
某种意义上来讲,问题被解决了,但是用的方式并不完美。也就是说,解决问题的方法,并不像我们开始时那么简单了。我们需要一种确定方式,独立于查询字符串的顺序,只要它们相同,就不要再次缓存数据。因此我们需要对查询的字符串进行排序。
现在我们开始为这个想法写代码:
$url = request()->url();
$queryParams = request()->query();
//对查询参数按照键名排序
ksort($queryParams);
//将查询数组转换为查询字符串
$queryString = http_build_query($queryParams);
$fullUrl = "{$url}?{$queryString}";
return Cache::remember($fullUrl, $minutes, function () use ($data) {
return $data;
});
思路是这样的,我们只需使用 query()
获取 URL 上的查询参数的关联数组,然后使用 ksort
对key
(而不是值)进行排序。 有 ksort
函数对数组按照键名进行排序,所以我们不需要再为排序的事情头疼。 然后把排序后的数组用 http_build_query()
构建查询用字符串,再重新与 URL 组合作为 rememberKey
的值。
这样一来,如果用户访问 yourdomain.com/products?sort_by=price&page=2
,它就会与 yourdomain.com/products?page=2&sort_by=price
相同。即使 URL 根据请求看起来有点不同,它们也会共用同一个缓存数据。
你还可以稍微『花哨』些,比如像这样把 $fullUrl
用 sha1
进行加密:
$url = request()->url();
$queryParams = request()->query();
ksort($queryParams);
$queryString = http_build_query($queryParams);
$fullUrl = "{$url}?{$queryString}";
$rememberKey = sha1($fullUrl);
return Cache::remember($rememberKey, $minutes, function () use ($data) {
return $data;
});
这里是下班了还在不停翻译的小骏蜂~
写代码这件事情,可以是一个人加上一群人的狂欢,毕竟很酷!
更多资讯教程可以上 Laravel 资讯站 查看~
本文翻译改编自 JuanDMeGon 的 Utilizing Laravel’s Cache with Query Params
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)