alpshq / statamic-cache-evader
Statamic 插件,帮助您绕过静态缓存并在缓存页面支持表单。
Requires
- statamic/cms: ^3.3
README
缓存绕过
Statamic 3 的缓存绕过
此插件提供了多种简单的方法来在缓存页面中提供 未缓存内容,并使在缓存页面上使用 Statamic 表单成为可能。
您可以做什么
支持
如果您喜欢这个插件,请考虑关注我的Twitter。如果您有功能请求,请随时通过打开GitHub问题来发起讨论。如果您有任何进一步的问题或想与我讨论合作机会,请给我发邮件到hello@jakub.io。
安装
您可以使用 composer 安装此插件
composer require alpshq/statamic-cache-evader
或者,您可以通过导航到控制面板中的Statamic 市场place并搜索 Cache Evader
来安装插件。
用法:基于 HTTP GET 参数的缓存绕过
基本上,您可以在任何URL中添加带有 任何 值的 GET 参数 _nc
来绕过缓存。
修改器
要添加相应的 HTTP 参数名称到任何URL,您可以使用内置的修改器 evade_cache
<a href="{{ current_url | evade_cache }}">Link to current (uncached) URL</a>
缓存绕过是如何工作的?
- 插件将用插件的 StaticCache 中间件替换 Statamic 的默认缓存中间件。
- 替换的中件将检查请求中是否包含缓存绕过参数。如果找到参数,则绕过缓存。如果没有,则应用 Statamic 的默认行为。
用法:表单
为了使您的表单在缓存环境中正常工作,请确保在关闭 </body>
标签之前添加 {{ cache_evader_scripts }} 标签。您可以在包含表单的每个页面上添加它,或者将其添加到全局布局中。
<!doctype html> <html> <head> ... </head> <body> {{ template_content }} ... {{ cache_evader_scripts }} </body> </html>
此标签将加载一个脚本,该脚本将为所有表单添加一个名为 _xsrf_token
且值为 XSRF cookie 的隐藏输入字段。
SpoofXsrfHeader 中间件将确保添加的字段被默认的 Laravel CSRF 保护中间件验证。
为了为用户提供有意义的错误和成功消息,您需要确保表单重定向到 未缓存 页面。在您的表单中添加包含前面提到的缓存绕过 HTTP 参数的 _redirect
和 _error_redirect
链接。最简单的方法是使用 evade_cache
修改器。
{{ form:create handle="contact-form" }} <input type="hidden" name="_redirect" value="{{ current_url | evade_cache }}" /> <input type="hidden" name="_error_redirect" value="{{ current_url | evade_cache }}" /> <!-- Your fields, buttons, success & error messages ... --> {{ /form:create }}
提交后,上述表单将重定向您到当前页面的未缓存版本,显示所有动态内容,例如错误和成功消息。
就是这样。您的表单将像没有缓存一样工作。
它具体是如何工作的?
- 您使用{{ cache_evader_scripts }}标签引入的脚本,该脚本会遍历所有表单,并通过添加一个名为
_xsrf_token
的隐藏输入字段,将当前的XSRF-TOKEN
cookie值附加到表单中。 - 如果没有这样的cookie存在(尤其是在您使用
full
缓存策略,并且当前用户由静态文件缓存提供服务时,这种情况尤为常见)- 脚本将对
cache-evader.ping
路由(/cache-evader/ping
)发起一个轻量级的fetch请求。 - Laravel将响应并附带
XSRF-TOKEN
cookie。 - 所有后续的访问和请求都可以访问到
XSRF-TOKEN
cookie,并且不会再次发起fetch请求。
- 脚本将对
SpoofXsrfHeader
中间件将请求的x-xsrf-token
头填充为_xsrf_token
字段的值。它基本上复制了当前的SPA行为,这在Laravel文档中有所提及。灵感来自Laravel的表单方法欺骗。
用法:将未缓存的组件作为缓存页面的部分注入
如果您能够在页面上显示动态内容
的同时利用Statamic的完整缓存策略,那不是很好吗?
无需再寻找——您已经找到了解决方案。借助您缓存页面中的未缓存
组件,您可以同时享受两者之所长。
设置方法
要启用自定义组件的注入,请确保在</body>
标签之前添加{{ cache_evader_scripts }}标签。您可以在使用{{ cache_evader_partial }}
标签的每个页面上添加它,或者将其添加到全局布局中。
<!doctype html> <html> <head> ... </head> <body> {{ template_content }} ... {{ cache_evader_scripts }} </body> </html>
该标签将加载一个脚本,通过为每个组件发送立即的fetch
请求来获取您未缓存的组件的内容。fetch请求将绕过缓存并加载您在组件中指定的任何动态内容。
基本用法
首先,创建一个包含动态内容的简单组件:partials/user.antlers.html
。
<!-- Your partial with dynamic content -->
{{ if logged_in }}
Welcome {{ current_user:email }}
{{ else }}
Please login.
{{ /if }}
现在,只需在模板中使用{{ cache_evader_partial }}
标签包含该组件即可。
<!-- Your template --> {{ cache_evader_partial:user }} <!-- ^^^^ -> This is the file name of the partial. -->
就是这样。您的完全缓存的页面
现在将始终显示用户的电子邮件!
参数
您可以在组件中添加任意数量的参数。您可以在组件中作为常规变量访问这些参数。
重要
请注意,参数是公开可见的——不要使用参数共享机密!
<!-- Your partial with dynamic content --> {{ if logged_in }} Welcome {{ current_user:email }} {{ else }} Please <a href="{{ login_url }}">login</a>. {{ /if }}
<!-- Your template -->
{{ cache_evader_partial:user login_url="/login" }}
显示加载消息
您可以通过将加载指示器包裹在标签对中来显示加载消息或指示器。
<!-- Your template -->
{{ cache_evader_partial src="user" login_url="/login" }}
Loading login state ...
{{ /cache_evader_partial }}
占位符元素
当您使用{{ cache_evader_partial }}
标签包含组件时,将渲染一个占位符div
而不是组件。占位符最终将被组件的内容替换。
您可以通过添加一个wrap
参数来更改占位符:{{ cache_evader_partial src="..." wrap="span" }}
。
包装组件内容
组件的内容将包装在div
元素中。您可以通过在组件中渲染单个根元素来避免这种行为。
这将包裹在div
中
<span> Welcome {{ current_user:email }}! </span> <a href="{{ logout_url }}">Not {{ current_user:email }}?</a>
这将不会包裹在div
中
<p> <span> Welcome {{ current_user:email }}! </span> <a href="{{ logout_url }}">Not {{ current_user:email }}?</a> </p>
脚本标签
是的!您可以在您的部分中包含脚本标签。它们将被执行。
<!-- Your partial with dynamic content --> {{ if logged_in }} Welcome {{ current_user:email }} {{ else }} Please <a href="{{ login_url }}">login</a>. {{ /if }} <script src="{{ mix src='/js/user.js' }}"></script>
JavaScript 插件
在发送 fetch 请求之前
在将每个 fetch 请求发送到您的服务器之前,在占位符元素上触发 cacheEvaderBeforeInject
事件。您可以通过在事件上调用 preventDefault()
来取消 fetch 请求。
window.addEventListener('cacheEvaderBeforeInject', ev => { ev.preventDefault(); // No fetch request is sent. // ev.target -- The placeholder element // ev.detail -- See below which properties are available. });
事件将有一个 detail
属性,其中包含请求发送到的 URL 以及您提供给部分的全部参数。
内容注入之后
在您的部分动态内容被检索并注入到 DOM 之后,在注入元素上触发 cacheEvaderAfterInject
事件。
window.addEventListener('cacheEvaderAfterInject', ev => { // ev.target -- See below what the target will be. // ev.detail -- See below which properties are available. });
事件 target
的值将是您的部分的外部包装元素。如果您的部分只有一个根元素,则 target
的值将是您的根元素。否则它将是一个包装 div
。
事件将有一个 detail
属性,其中包含请求发送到的 URL、您提供给部分的全部参数以及服务器的响应。
动态部分是如何详细工作的?
- 当使用
{{ cache_evader_partial }}
标签时,将渲染一个不带实际内容的占位符。 - 您使用
{{ cache_evader_scripts }}
标签添加到浏览器中的 JavaScript 将遍历每个占位符,并向服务器发送 fetch 请求 - 您的服务器渲染部分并将其发送到浏览器
- 占位符将被实际内容替换
配置
您可以将配置文件发布以修改默认参数名称(_nc
)和默认值(!
)
php artisan vendor:publish --tag=cache-evader-config
您可以在 config/statamic/cache-evader.php
中找到已发布的 配置文件 - 查看它以了解各种选项的解释。
安全性
如果您遇到任何与安全相关的问题,请直接通过电子邮件联系 jakub@alps.dev 而不是打开一个问题。所有与安全相关的问题都将得到及时解决。
许可
MIT -- 请参阅 许可文件。