You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 08:52:33