Skip to content

注意,浏览器必须创建成功后使用浏览器调用

基础版本 - 单请求处理

csharp
private void 创建URL请求ToolStripMenuItem_Click(object sender, EventArgs e)
{
    if (BrowserEvent.mainbrowser_.IsValid)
    {
        FBroSharpRequest sharp_request = new FBroSharpRequest();
        sharp_request.SetURL("https://api.fbrowser.site:8443/");
        sharp_request.SetMethod("GET");

        //添加协议头,这里用list添加,只添加了一个UA
        List<FBroSharpStringMap> heard_list = new List<FBroSharpStringMap>();

        heard_list.Add(new FBroSharpStringMap
        {
            key = "User-Agent",
            value = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.97 Safari/537.36 Core/1.116.438.400 QQBrowser/13.0.6071.400"
        });
        sharp_request.SetHeaderMap_Array(heard_list);

        // FBroSharpRequestContext sharp_request_context;
        URLEvent sharp_event = new URLEvent();
        BrowserEvent.mainbrowser_.GetMainFrame().CreateURLRequest(sharp_request, sharp_event, 123456);
    }
}

其中 BrowserEvent.mainbrowser_ 是 FBroSharpBrowser

基础URLEvent类(单请求版本)

csharp
public class URLEvent : FBroSharpURLEvent
{
    //用于存放全部数据
    private MemoryStream responseStream_;

    private BinaryWriter writer_;

    public override void Start(long flag, IFBroSharpURLRequest request)
    {
        responseStream_ = new MemoryStream();
        writer_ = new BinaryWriter(responseStream_);

        Console.WriteLine("Name:{0} Flag:{1} Request url:{2} Referrer url:{3}", MethodBase.GetCurrentMethod().Name, flag, request.GetRequestStatus(), request.GetRequest().GetURL(), request.GetRequest().GetReferrerURL());
    }

    public override void End(long flag)
    {
        Console.WriteLine("Name:{0} Flag:{1}", MethodBase.GetCurrentMethod().Name, flag);
       
        writer_ = null;
        responseStream_ = null;
       
    }

    public override bool GetAuthCredentials(long flag, bool isProxy, string host, int port, string realm, string scheme, IFBroSharpAuthCallback callback)
    {
        Console.WriteLine("Name:{0} Flag:{1}", MethodBase.GetCurrentMethod().Name, flag);
        return false;
    }

    public override void OnDownloadData(long flag, IFBroSharpURLRequest request, Stream data)
    {
        Console.WriteLine("Name:{0} Flag:{1} RequestStatus:{2}", MethodBase.GetCurrentMethod().Name, flag, request.GetRequestStatus());

        //如果存在多数据这个会多次调用本事件,因此数据先进行暂存到writer_中
        var readBytes = new byte[data.Length];
        data.Read(readBytes, 0, readBytes.Length);
        writer_.Write(readBytes);
    }

    public override void OnDownloadProgress(long flag, IFBroSharpURLRequest request, long current, long total)
    {
        Console.WriteLine("Name:{0} Flag:{1} RequestStatus:{2}", MethodBase.GetCurrentMethod().Name, flag, request.GetRequestStatus());
    }

    public override void OnRequestComplete(long flag, IFBroSharpURLRequest request)
    {
        Console.WriteLine("Name:{0} Flag:{1} RequestStatus:{2}", MethodBase.GetCurrentMethod().Name, flag, request.GetRequestStatus());

        //执行完毕再显示数据
        Console.WriteLine(Encoding.UTF8.GetString(responseStream_.ToArray()));

    }

    public override void OnUploadProgress(long flag, IFBroSharpURLRequest request, long current, long total)
    {
        Console.WriteLine("Name:{0} Flag:{1} RequestStatus:{2}", MethodBase.GetCurrentMethod().Name, flag, request.GetRequestStatus());
    }
}

🚀 优化版本 - 支持多并发请求的安全隔离

优化后的使用方式 - 共享URLEvent实例处理多个请求

csharp
private void 创建多并发URL请求_Click(object sender, EventArgs e)
{
    var browser = BrowserList.data[0];
    if (browser.IsValid)
    {
        // 创建共享的URLEvent实例处理多个请求
        URLEvent sharedCallback = new URLEvent();
        
        // 订阅数据接收事件
        sharedCallback.DataReceived += (flag, data) =>
        {
            this.Invoke(new Action(() =>
            {
                Console.WriteLine($"Flag {flag} 接收到数据: {data}");
                MessageBox.Show($"请求 {flag} 接收到数据:\n{data}", $"请求结果 - Flag {flag}", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }));
        };
        
        // 订阅请求完成事件
        sharedCallback.RequestCompleted += (flag) =>
        {
            this.Invoke(new Action(() =>
            {
                Console.WriteLine($"请求 {flag} 已完成");
            }));
        };

        // 发起多个并发请求,使用不同的flag进行数据隔离
        string[] urls = {
            "https://ipinfo.io/json",
            "https://httpbin.org/ip",
            "https://api.github.com"
        };

        for (int i = 0; i < urls.Length; i++)
        {
            FBroSharpRequest request = new FBroSharpRequest();
            request.SetURL(urls[i]);
            request.SetMethod("GET");

            List<FBroSharpStringMap> headers = new List<FBroSharpStringMap>();
            headers.Add(new FBroSharpStringMap
            {
                key = "User-Agent",
                value = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.97 Safari/537.36"
            });
            headers.Add(new FBroSharpStringMap
            {
                key = "accept",
                value = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
            });
            request.SetHeaderMap_Array(headers);

            // 使用不同的flag来区分请求:1000, 1001, 1002
            long flag = 1000 + i;
            Console.WriteLine($"发起请求 Flag {flag} 到 {urls[i]}");
            
            browser.GetMainFrame().CreateURLRequest(request, sharedCallback, flag);
        }
    }
}

🎯 优化后的URLEvent类 - 支持多并发请求安全隔离

csharp
//URL事件回调 - 优化版本:支持多并发请求的安全隔离
public class URLEvent: FBroSharpURLEvent
{
    // 数据接收完成事件 - 添加flag参数来区分不同请求
    public event Action<long, string> DataReceived;
    public event Action<long> RequestCompleted;
    
    // 使用字典来存储不同请求的数据流,key是flag
    private Dictionary<long, MemoryStream> responseStreams = new Dictionary<long, MemoryStream>();
    private Dictionary<long, BinaryWriter> writers = new Dictionary<long, BinaryWriter>();
    private object lockObject = new object(); // 线程安全锁
    

    public override void Start(long flag, IFBroSharpURLRequest request)
    {
        Console.WriteLine("Name:{0} Flag:{1} Request url:{2} Referrer url:{3}", 
            MethodBase.GetCurrentMethod().Name, flag, request.GetRequest().GetURL(), request.GetRequest().GetReferrerURL());
        
        lock (lockObject)
        {
            // 为每个flag创建独立的数据流
            responseStreams[flag] = new MemoryStream();
            writers[flag] = new BinaryWriter(responseStreams[flag]);
        }
    }

    public override void End(long flag)
    {
        Console.WriteLine("Name:{0} Flag:{1}", MethodBase.GetCurrentMethod().Name, flag);
        
        lock (lockObject)
        {
            // 清理资源
            if (writers.ContainsKey(flag))
            {
                writers[flag]?.Dispose();
                writers.Remove(flag);
            }
            
            if (responseStreams.ContainsKey(flag))
            {
                responseStreams[flag]?.Dispose();
                responseStreams.Remove(flag);
            }
        }
    }

    public override bool GetAuthCredentials(long flag, bool isProxy, string host, int port, string realm, string scheme, IFBroSharpAuthCallback callback)
    {
        Console.WriteLine("Name:{0} Flag:{1}", MethodBase.GetCurrentMethod().Name, flag); 
        return false;
    }

    public override void OnDownloadData(long flag, IFBroSharpURLRequest request, Stream data)
    {
        Console.WriteLine("Name:{0} Flag:{1} RequestStatus:{2}", MethodBase.GetCurrentMethod().Name, flag, request.GetRequestStatus());
        
        try
        {
            lock (lockObject)
            {
                if (writers.ContainsKey(flag) && responseStreams.ContainsKey(flag))
                {
                    // 如果存在多数据这个会多次调用本事件,因此数据先进行暂存到writer_中
                    var readBytes = new byte[data.Length];
                    data.Read(readBytes, 0, readBytes.Length);
                    writers[flag].Write(readBytes);
                    
                    Console.WriteLine($"Flag {flag} 数据长度: {readBytes.Length} 字节");
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Flag {flag} 读取流数据时发生错误: {ex.Message}");
        }
    }

    public override void OnDownloadProgress(long flag, IFBroSharpURLRequest request, long current, long total)
    {
        Console.WriteLine("Name:{0} Flag:{1} RequestStatus:{2} Progress:{3}/{4}", 
            MethodBase.GetCurrentMethod().Name, flag, request.GetRequestStatus(), current, total);
    }

    public override void OnRequestComplete(long flag, IFBroSharpURLRequest request)
    {
        Console.WriteLine("Name:{0} Flag:{1} RequestStatus:{2}", MethodBase.GetCurrentMethod().Name, flag, request.GetRequestStatus());
        
        // 请求完成时,获取完整数据并触发事件
        string completeData = "";
        lock (lockObject)
        {
            if (responseStreams.ContainsKey(flag))
            {
                // 执行完毕再显示数据
                byte[] responseBytes = responseStreams[flag].ToArray();
                completeData = Encoding.UTF8.GetString(responseBytes);
                
                Console.WriteLine($"Flag {flag} 完整响应数据: {completeData}");
            }
        }
        
        if (!string.IsNullOrEmpty(completeData))
        {
            DataReceived?.Invoke(flag, completeData);
        }
        
        // 触发请求完成事件
        RequestCompleted?.Invoke(flag);
    }

    public override void OnUploadProgress(long flag, IFBroSharpURLRequest request, long current, long total)
    {
        Console.WriteLine("Name:{0} Flag:{1} RequestStatus:{2} Upload:{3}/{4}", 
            MethodBase.GetCurrentMethod().Name, flag, request.GetRequestStatus(), current, total);
    }
}

📊 新旧版本对比

特性基础版本优化版本
多请求支持❌ 只能处理单个请求✅ 支持多个并发请求
数据隔离❌ 数据会混乱✅ 按flag完全隔离
线程安全❌ 不支持并发✅ 完全线程安全
事件通知❌ 只有控制台输出✅ 事件回调通知UI
资源管理⚠️ 基础清理✅ 完善的资源管理
数据处理✅ MemoryStream✅ Dictionary<flag, MemoryStream>
错误处理⚠️ 基础✅ 完善的异常处理

🎯 核心优势

多请求安全隔离

  • 使用 Dictionary<long, MemoryStream> 按 flag 隔离不同请求的数据
  • 每个请求的数据完全独立,不会混乱

线程安全保证

  • 所有字典操作都有锁保护
  • 支持多个浏览器同时发起请求

事件驱动架构

  • DataReceived 事件:Action<long, string> 获取完整数据
  • RequestCompleted 事件:Action<long> 通知请求完成

完善的资源管理

  • 自动清理每个 flag 对应的流和写入器
  • 防止内存泄漏

保持高效的数据处理

  • 继承 MD 文档中的 MemoryStream + BinaryWriter 方式
  • 适合处理二进制数据和大文件

🚀 使用场景

  1. 单个请求:可以使用任一版本
  2. 多个串行请求:推荐使用优化版本
  3. 多个并发请求:必须使用优化版本
  4. 多浏览器环境:推荐使用优化版本
  5. 需要UI反馈:推荐使用优化版本(支持事件)

优化版本完全向下兼容,可以作为通用解决方案使用!

如果文档对您有帮助,欢迎 请喝咖啡 ☕ | 软件发布 | 源码购买