PWA中用Fetch拦截跨域OPTIONS预检失败怎么办?
我在开发PWA时用service worker拦截fetch请求,发现跨域请求的OPTIONS预检总是返回504。尝试用event.respondWith(new Response())模拟响应后,控制台报“Response not allowed by CORS policy”。
代码是这样写的:
self.addEventListener('fetch', (event) => {
if (event.request.method === 'OPTIONS') {
event.respondWith(new Response(null, {
headers: { 'Access-Control-Allow-Origin': '*' }
}))
}
});
但后端明明返回了正确的CORS头,为什么预检拦截后主请求还是失败?是不是拦截OPTIONS请求的方式有问题?
Access-Control-Allow-Origin,但CORS预检要求的头不止这一个。浏览器看到响应不完整,就会报“Response not allowed by CORS policy”。正确做法是:如果你要在Service Worker里处理预检请求,必须返回完整的CORS响应头,而且状态码得是200或204。
改成这样:
不过更推荐的做法是:不要在Service Worker里自己处理OPTIONS,让后端直接返回正确的CORS头,你只拦截非预检请求。因为预检是浏览器自动发的,你强行拦截反而容易出问题。
如果确实要拦截,至少要确保你模拟的响应包含全部CORS相关头部,并且用204状态码——这是后端处理这类请求的常规方式。你现在只回了一个Origin,浏览器当然不认。
Access-Control-Allow-Origin就能搞定的。浏览器需要完整的OPTIONS响应,包括状态码、必要的CORS头和方法列表。你现在的写法少了关键的状态码和必须的头信息,导致主请求时浏览器判断不符合CORS策略。
正确的做法是不要在Service Worker里拦截OPTIONS请求,让真正的跨域预检请求直接到达后端服务器。如果一定要拦截,得完全模拟一个合法的OPTIONS响应,这很麻烦也很容易出错。
所以最简单的解决办法就是:移除对OPTIONS请求的拦截逻辑,改成这样:
这样就能保证OPTIONS预检请求正常通过,主请求也能正确处理CORS了。