注意,浏览器必须创建成功后使用浏览器调用
基础版本 - 单请求处理
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 方式
- 适合处理二进制数据和大文件
🚀 使用场景
- 单个请求:可以使用任一版本
- 多个串行请求:推荐使用优化版本
- 多个并发请求:必须使用优化版本
- 多浏览器环境:推荐使用优化版本
- 需要UI反馈:推荐使用优化版本(支持事件)
优化版本完全向下兼容,可以作为通用解决方案使用!