Flutter Web/PWA关闭标签或应用时调用API失败问题求助
关闭浏览器标签页/PWA时调用API失败问题
我尝试在用户关闭运行应用的标签页或已安装的PWA应用时调用API,但当前代码无法正常工作:
late String token; setUserToken() async { token = await FirebaseAuth.instance.currentUser!.getIdToken(true); } @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); // signOut(); html.window.onBeforeUnload.listen((event) async { // do something print(token); print("closing"); http.delete( Uri.parse( '${Helpers().apiUrl()}/location', ), headers: { 'Authorization': 'Bearer $token', 'Content-Type': 'application/json' }); }); setUserToken(); }
我也尝试过使用await http.delete。
补充说明
本地云函数调用该API时可以正常运行,但日志中出现以下内容:
2022-11-06T16:57:48.838Z OPTIONS /location
Function execution took 1936 ms. Finished with status code: 204
问题原因及修复方案
核心问题
- Token初始化时机问题:
setUserToken是异步方法,initState中直接调用未等待完成,导致页面卸载触发事件时,token可能还未赋值,或者处于未初始化状态。 - 浏览器卸载事件的请求限制:普通
http请求在onBeforeUnload事件中容易被浏览器中断,因为页面即将卸载,浏览器会主动终止未完成的网络请求。
具体修复步骤
- 触发事件时实时获取Token:避免依赖提前初始化的
token,在事件触发时重新获取,既解决初始化时机问题,也能避免Token过期。 - 使用支持页面卸载的请求方式:改用浏览器的Fetch API并开启
keepalive选项,确保请求能在页面卸载后完成。
修改后的代码:
@override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); html.window.onBeforeUnload.listen((event) async { // 实时获取有效Token final token = await FirebaseAuth.instance.currentUser!.getIdToken(true); print(token); print("closing"); // 使用Fetch API并开启keepalive final apiUrl = '${Helpers().apiUrl()}/location'; await html.fetch(apiUrl, { 'method': 'DELETE', 'headers': { 'Authorization': 'Bearer $token', 'Content-Type': 'application/json' }, 'keepalive': true, // 关键配置:告知浏览器保留请求直到完成 }); }); }
额外检查
- CORS配置:虽然OPTIONS请求返回204(预检通过),但需确认服务器端允许带
Authorization头的DELETE请求,响应头需包含Access-Control-Allow-Headers: Authorization, Content-Type。 - 错误处理:可以给Fetch请求添加简单的错误捕获,方便排查问题:
try { await html.fetch(apiUrl, { /* ...配置... */ }); } catch (e) { print('卸载时请求失败: $e'); }
内容的提问来源于stack exchange,提问作者AlienDecoy
相关产品推荐
相关产品推荐

