在公司内部署了一套开源的客户管理系统 SuiteCRM, 具体流程参考:Ubuntu Server 22.04 部署安装开源 CRM SuiteCRM 7.14。
但是遇到了一个非常影响体验的问题,经常点击返回按钮报错 ERR_CACHE_MISS。
复现步骤
- 进入一个超过两页的列表,例如联系人列表
- 进入列表页第二页,即点击下一页
- 选择一个联系人,点击,查看详情
- 点击浏览器的返回按钮
此时浏览器报错:ERR_CACHE_MISS
详细报错信息
中文报错信息:
是否重新提交表单? 要正确显示此网页,请重新提交你之前输入的数据。通过执行此操作,你将重复此页面之前执行的任何操作。 刷新以重新提交加载此页面所需的数据。 ERR_CACHE_MISS
类似问题
- https://community.suitecrm.com/t/using-browser-back-button-causes-err-cache-miss/68572/16
- https://github.com/salesagility/SuiteCRM/issues/7321
这个是 POST 搜索操作,引起的。而且,可以在出现 ERR_CACHE_MISS 错误之后,再点一次回退按钮就能解决。
但是,我目前遇到的,解决不了。再点一次回退,实际上就回到了列表首页,而不是列表的第二页。
浏览器为何会报 ERR_CACHE_MISS 这个错误呢?
这里的解释非常详细:
https://stackoverflow.com/questions/19215637/navigate-back-with-php-form-submission
引用一下里面的例子:
- 用户填写表格 (form),并提交 (submit)
- 服务器端处理提交的 post 数据,然后返回一个新的页面,并标注不要缓存 (not cacheable)
- 在返回的新页面中,用户又继续进入了下一个页面 (例如上门案例中的 detail 页)
- 这时用户点击浏览器的回退按钮。boom 爆炸了💥
于是就报 ERR_CACHE_MISS 错误了,跟 SuiteCRM 列表页问题完全是一个流程。
如果这是一个信用卡支付账单的功能,那么点击浏览器回退按钮,会造成两次 submit 操作。 即,重复支付订单。这个肯定是一个最严重的问题。所以,这里浏览器才会明确提示 ERR_CACHE_MISS 错误。
而为啥我的博客发布文章功能,就没有这个问题呢?
这也是里面给出的一个解决方案,就是 POST 数据之后,服务器再 302 redirect 重定向到一个 GET 页面 A。 此时,用户再点击其他页面,再点击 back 按钮,就是 GET 页面 A 了,而不是重新 POST。
这个解释很完美 👏
但是,这里也不能改成 302 跳转 GET 页面。。。
那我如果把列表页的请求,由 POST 改成 GET 不就好了?
另一个 ERR_CACHE_MISS 原因的概要描述
当你导航回包含表单提交的页面(通常是POST请求)时,Chrome可能会提示你重新提交表单。如果表单数据不再存在于缓存中,浏览器无法自动重新提交它,导致 "ERR_CACHE_MISS" 错误。
解决方法一:简单粗暴的继续使用
遇到这个错误时,点击浏览器的刷新按钮,然后在弹出的确认框中,点击继续。就能正常了。。。
但是每次遇到,都需要这样操作。体验还是非常糟糕的。
或者点击详情时,在新 tab 页中打开。
解决方法二:禁用浏览器的缓存
F12 打开开发者工具,在网络工具里,勾选"禁用缓存"。
这样,这个 ERR_CACHE_MISS 错误就不会再出现了。但是,由于 SuiteCRM 页面内的加载项太多,禁用后, 页面刷新缓慢。大量静态资源文件都需要重新从服务器拉取。
解决方法三:修改 SuiteCRM 源码
最后,还是通过修改 SuiteCRM PHP 源码的方式解决了,详细参考我整理的:
大结局:修改 PHP 代码解决 SuiteCRM ERR_CACHE_MISS 错误
下面的部分可以忽略了。
发送了个什么请求
引起这个错误时,对应的请求是什么?即,从详情页,返回列表时,到底是在调用哪个接口?
没有 GET/POST 信息,不知道是 GET 还是 POST
https://crm.sunzhongwei.com/index.php
- 请求头里没有 Cache-Control 及 Pragma 信息
- 响应头为空
第一次进入第二列表时, 正常的请求
请求:
POST https://crm.sunzhongwei.com/index.php
Cache-Control: max-age=0
Content-Type: application/x-www-form-urlencoded
响应头:
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Content-Type: text/html; charset=UTF-8
禁用浏览器缓存之后的正常请求
请求头:
POST https://crm.sunzhongwei.com/index.php
Cache-Control: no-cache
Pragma: no-cache
Content-Type: application/x-www-form-urlencoded
响应头:
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
列表首页为何是正常的
列表首页,在进入详情页,再返回时,就是正常的,没有这个错误。来看看首页的请求。
请求头:
- 请求头里没有 Cache-Control 及 Pragma 信息
GET https://crm.sunzhongwei.com/index.php?module=Contacts&action=index
响应头:
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
用我的博客来模拟
很奇怪,这么多年,第一次遇到这个问题。写过很多网站,也一次没有到这个错误。
于是我用博客的编辑页测试了一下:
POST 发布成功,然后点击浏览器 back 按钮。
请求
GET https://www.sunzhongwei.com/edit/aspnet-core-80-asp-append-version
提示,显示临时标头。禁用缓存以查看完整的标头。
响应头:
cache-control: no-cache, private
200 OK (从磁盘缓存)
但这并不是一回事,因为 SuiteCRM 是通过 POST 拉取列表,我这个博客是通过 GET 拉取编辑页。
浏览器 http 请求头 Cache-Control 有哪些值,区别是什么
请求时,Cache-Control 设置为 no-cache 与 max-age=0 有什么区别?
max-age=0 is a workaround for no-cache, because many old (HTTP/1.0) cache implementations don't support no-cache. Recently browsers are still using max-age=0 in "reloading" — for backward compatibility
Pragma: no-cache 有什么用,跟 Cache-Control:no-cache 有什么区别
- Pragma: no-cache:是 HTTP/1.0 的遗留指令。虽然许多现代浏览器和服务器仍然支持它,但它主要是为了向后兼容较旧的 HTTP/1.0 应用程序和设备。在 HTTP/1.1 及更高版本的环境中,Cache - Control头是推荐的缓存控制方式。
- Cache-Control: no-cache:是 HTTP/1.1 引入的缓存控制头。它提供了更灵活和精细的缓存控制机制,并且在现代的网络应用中被广泛使用。
参考
- https://world.siteground.com/kb/err_cache_miss
- https://stackoverflow.com/questions/19215637/navigate-back-with-php-form-submission
- https://www.cnblogs.com/cyamazing/p/18246375
微信关注我哦 👍
我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊, 查看更多联系方式