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

Dispose时同步事件处理器:避免WebSocket异常的解决方案

解决DevToolsSession释放时后台线程调用API的WebSocket异常问题

你的问题核心是DevToolsSession释放过程中,后台线程的RequestPaused事件处理器仍在执行,此时调用ContinueRequestWithoutModification会因为WebSocket已进入关闭状态而抛出异常。即使提前注销事件处理器,也无法阻止已经启动的异步逻辑继续执行。下面给你几个简洁可靠的解决方案:

方案1:先禁用监听,等待所有请求处理完成再释放

这是最稳妥的方式,从根源上切断新事件、等待已有任务完成后再释放Session:

[Test, Repeat(20)]
public void EventHandlersCanRunAfterDevToolsIsDisposed()
{
    using var driver = new ChromeDriver();
    var caughtExceptions = new List<Exception>();
    // 用并发集合跟踪正在处理的请求任务
    var activeTasks = new ConcurrentBag<Task>();

    using (var devToolsSession = driver.GetDevToolsSession(new DevToolsOptions { ProtocolVersion = 127 }))
    {
        var networkAdapter = new NetworkAdapter(devToolsSession);
        var fetch = new FetchAdapter(devToolsSession);
        var network = new V127Network(networkAdapter, fetch);

        var enableCommandSettings = new EnableCommandSettings
        {
            Patterns = new RequestPattern[]
            {
                new()
                {
                    RequestStage = RequestStage.Request,
                    UrlPattern = "*"
                }
            }
        };
        fetch.Enable(enableCommandSettings);

        network.RequestPaused += async (_, args) =>
        {
            var task = Task.Run(async () =>
            {
                try
                {
                    // Do some stuff...
                    await network.ContinueRequestWithoutModification(args.RequestData);
                }
                catch (Exception ex)
                {
                    lock (caughtExceptions)
                    {
                        caughtExceptions.Add(ex);
                    }
                }
            });
            activeTasks.Add(task);
        };

        driver.Url = "https://www.google.com";

        // 关键步骤:先禁用Fetch监听,停止接收新事件
        fetch.Disable();
        // 等待所有正在处理的请求任务完成
        Task.WaitAll(activeTasks.ToArray());
    } // 现在再释放DevToolsSession就安全了

    if (caughtExceptions.Count != 0)
        throw new AggregateException(caughtExceptions);
}

方案2:用CancellationToken控制异步操作

通过令牌在Session释放时取消未完成的操作,避免无效的API调用:

[Test, Repeat(20)]
public void EventHandlersCanRunAfterDevToolsIsDisposed()
{
    using var driver = new ChromeDriver();
    var caughtExceptions = new List<Exception>();
    using var cts = new CancellationTokenSource();

    using (var devToolsSession = driver.GetDevToolsSession(new DevToolsOptions { ProtocolVersion = 127 }))
    {
        var networkAdapter = new NetworkAdapter(devToolsSession);
        var fetch = new FetchAdapter(devToolsSession);
        var network = new V127Network(networkAdapter, fetch);

        var enableCommandSettings = new EnableCommandSettings
        {
            Patterns = new RequestPattern[]
            {
                new()
                {
                    RequestStage = RequestStage.Request,
                    UrlPattern = "*"
                }
            }
        };
        fetch.Enable(enableCommandSettings);

        network.RequestPaused += async (_, args) =>
        {
            try
            {
                // 先检查令牌是否已取消,避免执行后续操作
                cts.Token.ThrowIfCancellationRequested();
                
                // Do some stuff...
                await network.ContinueRequestWithoutModification(args.RequestData);
            }
            catch (OperationCanceledException)
            {
                // 取消操作无需记录异常
            }
            catch (Exception ex)
            {
                lock (caughtExceptions)
                {
                    caughtExceptions.Add(ex);
                }
            }
        };

        driver.Url = "https://www.google.com";
    } // 释放Session时触发取消
    cts.Cancel();

    if (caughtExceptions.Count != 0)
        throw new AggregateException(caughtExceptions);
}

方案3:兜底捕获特定异常(应急可用)

如果上面的方案仍有遗漏,可以在调用API时捕获WebSocketException并判断状态,忽略因Session关闭导致的异常:

network.RequestPaused += async (_, args) =>
{
    try
    {
        // Do some stuff...
        await network.ContinueRequestWithoutModification(args.RequestData);
    }
    catch (WebSocketException ex)
        when (ex.Message.Contains("CloseSent"))
    {
        // 忽略因Session关闭导致的无效调用异常
    }
    catch (Exception ex)
    {
        lock (caughtExceptions)
        {
            caughtExceptions.Add(ex);
        }
    }
};

优先推荐方案1,它从根源上避免了在Session关闭后执行API调用的情况,保证了线程安全。

内容的提问来源于stack exchange,提问作者Arnon Axelrod

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 23:59:52