服务工作者可以缓存 POST 请求吗?
Posted
技术标签:
【中文标题】服务工作者可以缓存 POST 请求吗?【英文标题】:Can service workers cache POST requests? 【发布时间】:2016-05-18 04:16:28 【问题描述】:我试图在 fetch 事件中缓存一个 POST 请求。
我使用了cache.put(event.request, response)
,但是返回的promise被TypeError: Invalid request method POST.
拒绝了。
当我尝试使用相同的 POST API 时,caches.match(event.request)
给了我 undefined。
但是当我对 GET 方法执行相同操作时,它起作用了:caches.match(event.request)
GET 请求正在给我一个响应。
如果他们不能,我们可以使用什么方法让应用真正离线?
【问题讨论】:
简单试试应该很容易:) 【参考方案1】:您无法使用缓存 API 缓存 POST 请求。请参阅https://w3c.github.io/ServiceWorker/#cache-put(第 4 点)。
spec 仓库中有相关讨论:https://github.com/slightlyoff/ServiceWorker/issues/693
ServiceWorker Cookbook 中介绍了一个有趣的解决方案:https://serviceworke.rs/request-deferrer.html 基本上,该解决方案将请求序列化到 IndexedDB。
【讨论】:
我没有看到任何关于 PATCH 或 DELETE 请求的内容。是一样的吗? 补丁和删除应该是一样的。你会在你的服务工作者中得到一个“获取”事件,你可以检查方法——GET、POST、PATCH、DELETE——然后做任何你需要做的事情。【参考方案2】:我在最近的一个带有 GraphQL API 的项目中使用了以下解决方案:我使用请求的序列化表示作为缓存键,将来自 API 路由的所有响应缓存在 IndexedDB 对象存储中。然后,如果网络不可用,我使用缓存作为备用:
// ServiceWorker.js
self.addEventListener('fetch', function(event)
// We will cache all POST requests to matching URLs
if(event.request.method === "POST" || event.request.url.href.match(/*...*/))
event.respondWith(
// First try to fetch the request from the server
fetch(event.request.clone())
// If it works, put the response into IndexedDB
.then(function(response)
// Compute a unique key for the POST request
var key = getPostId(request);
// Create a cache entry
var entry =
key: key,
response: serializeResponse(response),
timestamp: Date.now()
;
/* ... save entry to IndexedDB ... */
// Return the (fresh) response
return response;
)
.catch(function()
// If it does not work, return the cached response. If the cache does not
// contain a response for our request, it will give us a 503-response
var key = getPostId(request);
var cachedResponse = /* query IndexedDB using the key */;
return response;
)
);
)
function getPostId(request)
/* ... compute a unique key for the request incl. it's body: e.g. serialize it to a string */
这是我使用 Dexie.js 作为 IndexedDB 包装器的特定解决方案的full code。随意使用!
【讨论】:
虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review 对不起。我已更改答案以包含代码摘要(整个代码很长)。或者我是否应该发布整个代码而不管它的长度? sn-p 应该没问题。如果您只是发布指向您自己博客的链接,它看起来很像垃圾邮件。现在对我来说似乎好多了 如果您想推广您的博客Limits for self-promotion in answers,我可能会建议您阅读以下内容【参考方案3】:如果你说的是表单数据,那么你可以截取 fetch 事件,按照下面类似的方式读取表单数据,然后将数据保存到 indexedDB 中。
//service-worker.js
self.addEventListener('fetch', function(event)
if(event.request.method === "POST")
var newObj = ;
event.request.formData().then(formData =>
for(var pair of formData.entries())
var key = pair[0];
var value = pair[1];
newObj[key] = value;
).then( ...save object in indexedDB... )
)
【讨论】:
【参考方案4】:使用Cloud Firestore offline persistence 可以获得另一种提供完全离线体验的方法。
POST / PUT 请求在本地缓存数据库上执行,然后在用户恢复其互联网连接后立即自动同步到服务器(请注意,有 500 个离线请求的限制)。
遵循此解决方案要考虑的另一个方面是,如果多个用户具有同时同步的离线更改,则无法保证更改将在服务器上按正确的时间顺序执行,因为 Firestore 使用 先到先得逻辑。
【讨论】:
【参考方案5】:根据https://w3c.github.io/ServiceWorker/#cache-put(第4点)。
if(request.method !== "GET")
return Promise.reject('no-match')
【讨论】:
以上是关于服务工作者可以缓存 POST 请求吗?的主要内容,如果未能解决你的问题,请参考以下文章