Chrome扩展使用Socket.io连接本地服务器遇XHR Polling Error问题
问题:Chrome扩展中Socket.io连接本地服务器出现XHR Polling Error
尝试在Chrome Manifest V3扩展中使用Socket.io与本地服务器通信时,触发XHR Polling Error,但普通客户端连接正常。已尝试替换localhost为IP地址、指定WebSocket协议、配置CORS等操作,问题仍未解决。
相关代码如下:
manifest.json
{ "manifest_version": 3, "name": "DogadPrime Alerte", "version": "2.0", "description": "Ne manquez jamais un live de DogadPrime sur Twitch ainsi que les prochaines vidéos youtube grâce à des notifications instantanées !", "permissions": [ "notifications", "alarms", "storage", "activeTab", "webRequest" ], "minimum_chrome_version": "116", "host_permissions": ["http://localhost:3000/*"], "background": { "service_worker": "background.js", "type": "module" }, "icons": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" } }
background.js
import { io } from "https://cdn.jsdelivr.net/npm/socket.io-client@4.7.1/+esm"; const socketUrl = "http://localhost:3000/"; const socket = io(socketUrl, { transport: ["websocket"], }); console.log("Lancement de l'extension browser"); if (typeof browser === "undefined") { var browser = chrome; } function showNotificationTwitch(stream) { browser.notifications.create('twitch-streamer-alert', { type: 'basic', iconUrl: 'icons/icon48.png', title: `${stream.user_name} est en live !`, message: `Regardez maintenant sur Twitch : ${stream.title}`, priority: 2 }); } browser.notifications.onClicked.addListener(function (notificationId) { if (notificationId === 'twitch-streamer-alert') { const twitchChannelUrl = 'https://www.twitch.tv/dogadprime'; console.log('Ouverture de l\'URL Twitch:', twitchChannelUrl); browser.tabs.create({ url: twitchChannelUrl }); } }); // Événement lorsqu'une connexion est établie socket.on('connection', () => { console.log('Connexion au serveur'); }); socket.on('platformNotification', (data) => { console.log(data); const { platform, status, streamData } = data; if (platform == 'twitch' && status == true) { console.log('Le streamer est en direct !'); console.log('Détails du stream :', data.streamData); showNotificationTwitch(streamData); } else { console.log('Le streamer n\'est pas en direct.'); } }); socket.on('connect_error', (error) => { console.log('Erreur de connexion :', error); });
服务器端app.js
const express = require('express'); const http = require('http'); const socketIo = require('socket.io'); const fetch = require('node-fetch'); require('dotenv').config(); const app = express(); const server = http.createServer(app); const io = socketIo(server, { cors: { origin: "*", methods: ["GET", "POST"], }, }); const clientId = process.env.TWITCH_CLIENT_ID; const accessToken = process.env.TWITCH_ACCESS_TOKEN; const streamerName = 'sc2skyblue'; const twitchApiUrl = `https://api.twitch.tv/helix/streams?user_login=${streamerName}`; let isStreamerOnline = false; async function checkStreamerLive() { try { const response = await fetch(twitchApiUrl, { headers: { 'Client-ID': clientId, 'Authorization': `Bearer ${accessToken}` } }); const data = await response.json(); const currentlyOnline = data.data && data.data.length > 0; if (currentlyOnline && !isStreamerOnline) { io.emit('platformNotification', { platform: 'twitch', status: true, streamData: data.data[0] }); console.log("Le streamer est en direct. Notification envoyée."); } else if (!currentlyOnline && isStreamerOnline) { io.emit('platformNotification', { platform: 'twitch', status: false, streamData: null }); console.log("Le streamer est hors ligne. Notification envoyée."); } isStreamerOnline = currentlyOnline; } catch (error) { console.error('Erreur lors de la vérification du statut du streamer :', error); } } const checkInterval = 1 * 60 * 1000; // 1 minute setInterval(checkStreamerLive, checkInterval); io.on('connection', (socket) => { console.log('Un client est connecté'); socket.emit('welcome', { message: 'Bienvenue sur le serveur Socket.IO' }); socket.on('disconnect', () => { console.log('Un client s\'est déconnecté'); }); }); server.listen(3000, () => { console.log('Serveur en écoute sur le port 3000'); });
错误截图

解决方案
1. 修正客户端连接事件监听
客户端代码中监听连接成功的事件名错误,应使用connect而非connection:
// 修正前 socket.on('connection', () => { console.log('Connexion au serveur'); }); // 修正后 socket.on('connect', () => { console.log('Connexion au serveur'); });
2. 修复Socket.io传输配置
原代码中配置项transport为单数,正确键名是transports(复数),同时添加参数强制使用WebSocket:
const socket = io(socketUrl, { transports: ["websocket"], // 修正键名为复数 upgrade: false, // 禁用协议升级,强制使用WebSocket rejectUnauthorized: false, // 本地开发环境跳过证书验证 });
3. 完善服务器端CORS配置
针对Chrome扩展来源,明确允许chrome-extension://开头的地址:
const io = socketIo(server, { cors: { origin: (origin, callback) => { const allowedOrigins = ["http://localhost:3000", /^chrome-extension:\/\/.+/]; if (allowedOrigins.includes(origin) || !origin) { callback(null, true); } else { callback(new Error("Not allowed by CORS")); } }, methods: ["GET", "POST", "OPTIONS"], allowedHeaders: ["*"], credentials: true }, });
4. 更新扩展权限
在host_permissions中添加WebSocket协议的地址:
"host_permissions": ["http://localhost:3000/*", "ws://localhost:3000/*"]
5. 排查环境限制
- 确保扩展已启用开发者模式并正确加载
- 检查防火墙是否拦截
localhost:3000端口 - 确认本地服务器正常运行,无其他进程占用端口
内容的提问来源于stack exchange,提问作者Thomas A
相关产品推荐
相关产品推荐

