如何将前端变量传递至Service Worker?及JSON解析错误排查
问题分析与解决方案
前端Service Worker问题
1. Fetch请求格式错误(SyntaxError的直接诱因)
你在saveSubscription函数中设置了Content-Type: application/json,但body直接传入了对象——浏览器不会自动将对象转为JSON字符串,后端bodyParser.json()解析时会收到非JSON格式的内容,从而抛出SyntaxError: Unexpected token o in JSON at position 1。
修复代码:
// service.js(Service Worker文件) const saveSubscription = async (subscription, usrCode) => { const SERVER_URL = 'https://mywebsite:4000/save-subscription' const subscriptionStr = JSON.stringify(subscription); console.log(subscriptionStr); console.log(usrCode); const response = await fetch(SERVER_URL, { method: 'post', headers: { 'Content-Type' : 'application/json', }, // 必须用JSON.stringify将body转为JSON字符串 body : JSON.stringify({ subscription: subscriptionStr, usrCode: usrCode }) }) return response }
2. usrCode在Service Worker中输出undefined的问题
Service Worker运行在独立线程,无法直接访问主线程变量,你需要通过主线程向它传递usrCode:
主线程传递usrCode示例:
// 页面主线程JS文件 if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/service.js') .then(async (registration) => { const subscription = await registration.pushManager.subscribe(/* 你的订阅配置 */); const usrCode = '用户标识ID'; // 这里是你已获取到的正确usrCode // 向Service Worker发送消息传递参数 registration.active.postMessage({ type: 'SAVE_SUBSCRIPTION', subscription, usrCode }); }); }
Service Worker接收处理:
// service.js中添加消息监听 self.addEventListener('message', async (event) => { if (event.data.type === 'SAVE_SUBSCRIPTION') { const { subscription, usrCode } = event.data; await saveSubscription(subscription, usrCode); } }); // 保留修复后的saveSubscription函数 const saveSubscription = async (subscription, usrCode) => { // ... 上述修复后的代码 ... }
后端Node.js/Express问题
1. 函数调用参数错误
你调用saveToDatabase时,错误地将usrCode作为JSON.stringify的第二个参数传入,导致saveToDatabase的第二个参数usrCode为undefined,同时重复序列化了subscription(前端已完成字符串转换)。
修复代码:
// index.js(后端文件) app.post('/save-subscription', async (req, res) => { const usrCode = req.body.usrCode; const subscription = req.body.subscription; // 直接传递两个独立参数,无需再次JSON.stringify await saveToDatabase(subscription, usrCode); res.json({ message: 'success' }); })
2. 异步函数未正确封装
saveToDatabase标记为async,但内部使用回调形式的pool.getConnection,await无法等待回调完成,会导致请求提前返回且错误无法捕获。需要将回调转为Promise:
修复后的saveToDatabase:
const saveToDatabase = async (subscription, usrCode) => { return new Promise((resolve, reject) => { pool.getConnection(function (err, connection) { if (err) { reject(err); return; } console.log(usrCode); console.log(subscription); // 使用参数化查询规避SQL注入风险 const sql = 'INSERT INTO webpushsub (webpushsub_info, webpushsub_code) VALUES (?, ?)'; connection.query(sql, [subscription, usrCode], function (err, result, fields) { connection.release(); if (err) { reject(err); return; } console.log(result); resolve(result); }); }); }); }
3. 规避SQL注入风险
原代码直接将变量拼接进SQL语句,存在严重安全隐患,必须使用参数化查询(上述代码已修正)。
内容的提问来源于stack exchange,提问作者Moha
相关产品推荐
相关产品推荐

