你是否遇到过这样的开发痛点:内网环境无法访问外部API,需要通过代理进行调试?或者需要监控团队应用的HTTP请求流量?最近在.NET技术群里,很多开发者都在讨论一个共同问题:"如何快速实现一个灵活可控的HTTP代理服务器?"
据不完全统计,超过70%的企业级应用都需要代理服务器来处理网络请求,但市面上的代理工具要么功能单一,要么配置复杂。今天就带你用C#从零开始,10分钟内搭建一个功能完整的HTTP代理服务器,让你彻底掌握网络代理的核心原理和实现技巧!
为什么要自己开发HTTP代理服务器?
常见应用场景分析
在实际C#开发中,我们经常遇到这些痛点:
1. 开发环境限制:内网环境无法直接访问外部API
2. 请求监控需求:需要记录和分析HTTP请求数据
3. 访问控制:对特定域名或IP进行过滤
4. 性能优化:缓存频繁请求的响应数据
5. 负载均衡:将请求分发到不同的后端服务器
核心技术方案选型
本文采用HttpListener + Socket的混合方案,既保证了开发效率,又确保了核心功能的完整性。
基础HTTP代理服务器实现
完整可运行代码
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
publicclass BasicHttpProxyServer
{
private readonly int _port;
private TcpListener _listener;
privatebool _isRunning;
public BasicHttpProxyServer(int port = 8888)
{
_port = port;
}
/// <summary>
/// 启动代理服务器
/// </summary>
public async Task StartAsync()
{
_listener = new TcpListener(IPAddress.Any, _port);
_listener.Start();
_isRunning = true;
Console.WriteLine($"🚀 HTTP代理服务器已启动,监听端口: {_port}");
Console.WriteLine($"📖 浏览器代理设置: 127.0.0.1:{_port}");
while (_isRunning)
{
try
{
var client = await _listener.AcceptTcpClientAsync();
// 异步处理每个客户端连接,避免阻塞
_ = Task.Run(() => HandleClientAsync(client));
}
catch (Exception ex)
{
Console.WriteLine($"❌ 接受连接时出错: {ex.Message}");
}
}
}
/// <summary>
/// 处理客户端请求的核心方法
/// </summary>
private async Task HandleClientAsync(TcpClient client)
{
NetworkStream clientStream = null;
try
{
clientStream = client.GetStream();
// 读取HTTP请求头
var requestData = await ReadHttpRequestAsync(clientStream);
if (string.IsNullOrEmpty(requestData))
return;
Console.WriteLine($"📥 接收请求: {requestData.Split('\n')[0]}");
// 解析请求信息
var requestInfo = ParseHttpRequest(requestData);
if (requestInfo == null)
return;
// 处理CONNECT方法(HTTPS隧道)
if (requestInfo.Method.Equals("CONNECT", StringComparison.OrdinalIgnoreCase))
{
await HandleHttpsConnectAsync(clientStream, requestInfo);
}
else
{
// 处理普通HTTP请求
await HandleHttpRequestAsync(clientStream, requestInfo, requestData);
}
}
catch (Exception ex)
{
Console.WriteLine($"❌ 处理客户端请求时出错: {ex.Message}");
}
finally
{
clientStream?.Close();
client?.Close();
}
}
/// <summary>
/// 读取HTTP请求数据
/// </summary>
private async Task<string> ReadHttpRequestAsync(NetworkStream stream)
{
var buffer = new byte[4096];
var requestBuilder = new StringBuilder();
try
{
// 设置读取超时时间
stream.ReadTimeout = 5000;
while (true)
{
var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0) break;
var data = Encoding.UTF8.GetString(buffer, 0, bytesRead);
requestBuilder.Append(data);
// 检查是否读取完整的HTTP头部
if (requestBuilder.ToString().Contains("\r\n\r\n"))
break;
}
}
catch (Exception ex)
{
Console.WriteLine($"⚠️ 读取请求数据时出错: {ex.Message}");
return null;
}
return requestBuilder.ToString();
}
/// <summary>
/// 解析HTTP请求信息
/// </summary>
private RequestInfo ParseHttpRequest(string request)
{
try
{
var lines = request.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
if (lines.Length == 0) return null;
var requestLine = lines[0].Split(' ');
if (requestLine.Length < 3) return null;
var method = requestLine[0];
var url = requestLine[1];
var version = requestLine[2];
// 解析目标主机和端口
string host = "localhost";
int port = 80;
if (method.Equals("CONNECT", StringComparison.OrdinalIgnoreCase))
{
// CONNECT方法的URL格式: host:port
var parts = url.Split(':');
host = parts[0];
port = parts.Length > 1 ? int.Parse(parts[1]) : 443;
}
else
{
// 从Host头部获取主机信息
foreach (var line in lines)
{
if (line.StartsWith("Host:", StringComparison.OrdinalIgnoreCase))
{
var hostValue = line.Substring(5).Trim();
var hostParts = hostValue.Split(':');
host = hostParts[0];
port = hostParts.Length > 1 ? int.Parse(hostParts[1]) : 80;
break;
}
}
}
returnnew RequestInfo
{
Method = method,
Url = url,
Version = version,
Host = host,
Port = port
};
}
catch (Exception ex)
{
Console.WriteLine($"❌ 解析请求时出错: {ex.Message}");
return null;
}
}
/// <summary>
/// 处理HTTPS CONNECT请求(建立隧道)
/// </summary>
private async Task HandleHttpsConnectAsync(NetworkStream clientStream, RequestInfo requestInfo)
{
TcpClient targetClient = null;
NetworkStream targetStream = null;
try
{
// 连接目标服务器
targetClient = new TcpClient();
await targetClient.ConnectAsync(requestInfo.Host, requestInfo.Port);
targetStream = targetClient.GetStream();
// 向客户端发送连接成功响应
var response = "HTTP/1.1 200 Connection Established\r\n\r\n";
var responseBytes = Encoding.UTF8.GetBytes(response);
await clientStream.WriteAsync(responseBytes, 0, responseBytes.Length);
Console.WriteLine($"🔐 HTTPS隧道已建立: {requestInfo.Host}:{requestInfo.Port}");
// 开始双向数据转发
var task1 = ForwardDataAsync(clientStream, targetStream, "客户端->服务器");
var task2 = ForwardDataAsync(targetStream, clientStream, "服务器->客户端");
await Task.WhenAny(task1, task2);
}
catch (Exception ex)
{
Console.WriteLine($"❌ HTTPS隧道建立失败: {ex.Message}");
}
finally
{
targetStream?.Close();
targetClient?.Close();
}
}
/// <summary>
/// 数据转发方法(用于HTTPS隧道)
/// </summary>
private async Task ForwardDataAsync(NetworkStream from, NetworkStream to, string direction)
{
var buffer = new byte[4096];
try
{
while (true)
{
var bytesRead = await from.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0) break;
await to.WriteAsync(buffer, 0, bytesRead);
Console.WriteLine($"📡 数据转发 {direction}: {bytesRead} 字节");
}
}
catch (Exception ex)
{
Console.WriteLine($"⚠️ 数据转发中断 {direction}: {ex.Message}");
}
}
/// <summary>
/// 停止代理服务器
/// </summary>
public void Stop()
{
_isRunning = false;
_listener?.Stop();
Console.WriteLine("🛑 HTTP代理服务器已停止");
}
}
/// <summary>
/// 请求信息数据结构
/// </summary>
publicclass RequestInfo
{
publicstring Method { get; set; }
publicstring Url { get; set; }
publicstring Version { get; set; }
publicstring Host { get; set; }
publicint Port { get; set; }
}
/// <summary>
/// 程序入口点
/// </summary>
class Program
{
static async Task Main(string[] args)
{
var proxy = new BasicHttpProxyServer(8888);
Console.WriteLine("按 Ctrl+C 停止服务器");
Console.CancelKeyPress += (sender, e) =>
{
e.Cancel = true;
proxy.Stop();
Environment.Exit(0);
};
await proxy.StartAsync();
}
}
图片
使用说明
1. 编译运行:将代码保存为.cs文件,使用dotnet run
启动
2. 浏览器设置:将浏览器代理设置为127.0.0.1:8888
3. 测试验证:访问任意网站,查看控制台输出
常见坑点提醒
- 端口占用确保选择的端口未被其他程序占用
- 防火墙设置可能需要添加防火墙规则允许程序监听端口
- 超时处理网络超时会导致连接挂起,代码中已添加超时控制
方案二:带请求监控的高级代理服务器
功能增强点
在基础版本的基础上,我们来实现一个企业级的高级代理服务器,新增以下核心功能:
1. 请求监控:记录每个请求的详细信息和响应时间
2. 域名过滤:支持黑名单机制,自动阻止恶意域名访问
3. 统计分析:定时输出代理服务器运行统计
4. 日志导出:支持将请求日志导出为JSON格式
5. 性能监控:实时监控数据传输量和响应时间
核心监控代码实现
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Collections.Concurrent;
using System.Text.Json;
namespace AppBasicHttpProxyServer
{
/// <summary>
/// 带请求监控的高级代理服务器
/// </summary>
publicclass AdvancedHttpProxyServer
{
private readonly int _port;
private TcpListener _listener;
privatebool _isRunning;
// 请求监控和统计
private readonly ConcurrentQueue<RequestLog> _requestLogs;
private readonly ConcurrentDictionary<string, DomainStats> _domainStats;
private readonly object _statsLock = new object();
// 配置选项
private readonly ProxyConfig _config;
public AdvancedHttpProxyServer(int port = 8888, ProxyConfig config = null)
{
_port = port;
_requestLogs = new ConcurrentQueue<RequestLog>();
_domainStats = new ConcurrentDictionary<string, DomainStats>();
_config = config ?? new ProxyConfig();
// 启动监控任务
if (_config.EnableMonitoring)
{
_ = Task.Run(MonitoringTaskAsync);
}
// 启动日志清理任务
if (_config.EnableLogCleanup)
{
_ = Task.Run(LogCleanupTaskAsync);
}
}
/// <summary>
/// 启动代理服务器
/// </summary>
public async Task StartAsync()
{
_listener = new TcpListener(IPAddress.Any, _port);
_listener.Start();
_isRunning = true;
Console.WriteLine("🚀 高级HTTP代理服务器已启动");
Console.WriteLine($"📡 监听端口: {_port}");
Console.WriteLine($"📊 监控功能: {(_config.EnableMonitoring ? "启用" : "禁用")}");
Console.WriteLine($"📝 日志记录: {(_config.EnableLogging ? "启用" : "禁用")}");
Console.WriteLine($"🚫 域名过滤: {(_config.BlockedDomains.Any() ? "启用" : "禁用")}");
Console.WriteLine($"📖 浏览器代理设置: 127.0.0.1:{_port}");
Console.WriteLine(newstring('=', 50));
while (_isRunning)
{
try
{
var client = await _listener.AcceptTcpClientAsync();
// 异步处理每个客户端连接,避免阻塞
_ = Task.Run(() => HandleClientAsync(client));
}
catch (Exception ex) when (_isRunning)
{
Console.WriteLine($"❌ 接受连接时出错: {ex.Message}");
}
}
}
/// <summary>
/// 处理客户端请求的核心方法
/// </summary>
private async Task HandleClientAsync(TcpClient client)
{
NetworkStream clientStream = null;
RequestLog requestLog = new RequestLog
{
Timestamp = DateTime.Now,
ClientEndPoint = client.Client.RemoteEndPoint?.ToString()
};
try
{
clientStream = client.GetStream();
// 设置超时时间
client.ReceiveTimeout = _config.ReceiveTimeout;
client.SendTimeout = _config.SendTimeout;
// 读取HTTP请求头
var requestData = await ReadHttpRequestAsync(clientStream);
if (string.IsNullOrEmpty(requestData))
{
requestLog.Status = "Failed - Empty Request";
return;
}
// 解析请求信息
var requestInfo = ParseHttpRequest(requestData);
if (requestInfo == null)
{
requestLog.Status = "Failed - Parse Error";
return;
}
// 更新请求日志
requestLog.Method = requestInfo.Method;
requestLog.Host = requestInfo.Host;
requestLog.Url = requestInfo.Url;
requestLog.Port = requestInfo.Port;
// 检查域名过滤
if (IsDomainBlocked(requestInfo.Host))
{
await SendBlockedResponse(clientStream);
requestLog.Status = "Blocked";
requestLog.BytesTransferred = 0;
Console.WriteLine($"🚫 请求被阻止: {requestInfo.Host}");
return;
}
Console.WriteLine($"📥 [{DateTime.Now:HH:mm:ss}] {requestInfo.Method} {requestInfo.Host}:{requestInfo.Port}");
// 处理请求
if (requestInfo.Method.Equals("CONNECT", StringComparison.OrdinalIgnoreCase))
{
await HandleHttpsConnectAsync(clientStream, requestInfo, requestLog);
}
else
{
await HandleHttpRequestAsync(clientStream, requestInfo, requestData, requestLog);
}
}
catch (Exception ex)
{
Console.WriteLine($"❌ 处理客户端请求时出错: {ex.Message}");
requestLog.Status = $"Error - {ex.Message}";
}
finally
{
requestLog.EndTime = DateTime.Now;
requestLog.Duration = (requestLog.EndTime - requestLog.Timestamp).TotalMilliseconds;
// 记录请求日志
if (_config.EnableLogging)
{
_requestLogs.Enqueue(requestLog);
}
// 更新域名统计
UpdateDomainStats(requestLog);
clientStream?.Close();
client?.Close();
}
}
/// <summary>
/// 读取HTTP请求数据
/// </summary>
private async Task<string> ReadHttpRequestAsync(NetworkStream stream)
{
var buffer = new byte[4096];
var requestBuilder = new StringBuilder();
try
{
stream.ReadTimeout = _config.ReceiveTimeout;
while (true)
{
var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0) break;
var data = Encoding.UTF8.GetString(buffer, 0, bytesRead);
requestBuilder.Append(data);
// 检查是否读取完整的HTTP头部
if (requestBuilder.ToString().Contains("\r\n\r\n"))
break;
}
}
catch (Exception ex)
{
Console.WriteLine($"⚠️ 读取请求数据时出错: {ex.Message}");
return null;
}
return requestBuilder.ToString();
}
/// <summary>
/// 解析HTTP请求信息
/// </summary>
private RequestInfo ParseHttpRequest(string request)
{
try
{
var lines = request.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
if (lines.Length == 0) return null;
var requestLine = lines[0].Split(' ');
if (requestLine.Length < 3) return null;
var method = requestLine[0];
var url = requestLine[1];
var version = requestLine[2];
// 解析目标主机和端口
string host = "localhost";
int port = 80;
if (method.Equals("CONNECT", StringComparison.OrdinalIgnoreCase))
{
// CONNECT方法的URL格式: host:port
var parts = url.Split(':');
host = parts[0];
port = parts.Length > 1 ? int.Parse(parts[1]) : 443;
}
else
{
// 从Host头部获取主机信息
foreach (var line in lines)
{
if (line.StartsWith("Host:", StringComparison.OrdinalIgnoreCase))
{
var hostValue = line.Substring(5).Trim();
var hostParts = hostValue.Split(':');
host = hostParts[0];
port = hostParts.Length > 1 ? int.Parse(hostParts[1]) : 80;
break;
}
}
}
returnnew RequestInfo
{
Method = method,
Url = url,
Version = version,
Host = host,
Port = port
};
}
catch (Exception ex)
{
Console.WriteLine($"❌ 解析请求时出错: {ex.Message}");
return null;
}
}
/// <summary>
/// 处理HTTPS CONNECT请求(建立隧道)
/// </summary>
private async Task HandleHttpsConnectAsync(NetworkStream clientStream, RequestInfo requestInfo, RequestLog requestLog)
{
TcpClient targetClient = null;
NetworkStream targetStream = null;
try
{
// 连接目标服务器
targetClient = new TcpClient();
await targetClient.ConnectAsync(requestInfo.Host, requestInfo.Port);
targetStream = targetClient.GetStream();
// 向客户端发送连接成功响应
var response = "HTTP/1.1 200 Connection Established\r\n\r\n";
var responseBytes = Encoding.UTF8.GetBytes(response);
await clientStream.WriteAsync(responseBytes, 0, responseBytes.Length);
Console.WriteLine($"🔐 HTTPS隧道已建立: {requestInfo.Host}:{requestInfo.Port}");
requestLog.Status = "Connected";
// 开始双向数据转发
var task1 = ForwardDataAsync(clientStream, targetStream, requestLog, "客户端->服务器");
var task2 = ForwardDataAsync(targetStream, clientStream, requestLog, "服务器->客户端");
await Task.WhenAny(task1, task2);
requestLog.Status = "Completed";
}
catch (Exception ex)
{
Console.WriteLine($"❌ HTTPS隧道建立失败: {ex.Message}");
requestLog.Status = $"Failed - {ex.Message}";
}
finally
{
targetStream?.Close();
targetClient?.Close();
}
}
/// <summary>
/// 处理普通HTTP请求
/// </summary>
private async Task HandleHttpRequestAsync(NetworkStream clientStream, RequestInfo requestInfo, string requestData, RequestLog requestLog)
{
TcpClient targetClient = null;
NetworkStream targetStream = null;
try
{
// 连接目标服务器
targetClient = new TcpClient();
await targetClient.ConnectAsync(requestInfo.Host, requestInfo.Port);
targetStream = targetClient.GetStream();
// 转发请求到目标服务器
var requestBytes = Encoding.UTF8.GetBytes(requestData);
await targetStream.WriteAsync(requestBytes, 0, requestBytes.Length);
// 读取并转发响应
var buffer = new byte[4096];
while (true)
{
var bytesRead = await targetStream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0) break;
await clientStream.WriteAsync(buffer, 0, bytesRead);
requestLog.BytesTransferred += bytesRead;
}
requestLog.Status = "Completed";
Console.WriteLine($"✅ HTTP请求完成: {requestInfo.Host} ({requestLog.BytesTransferred} 字节)");
}
catch (Exception ex)
{
Console.WriteLine($"❌ HTTP请求处理失败: {ex.Message}");
requestLog.Status = $"Failed - {ex.Message}";
}
finally
{
targetStream?.Close();
targetClient?.Close();
}
}
/// <summary>
/// 数据转发方法(用于HTTPS隧道)
/// </summary>
private async Task ForwardDataAsync(NetworkStream from, NetworkStream to, RequestLog requestLog, string direction)
{
var buffer = new byte[4096];
try
{
while (true)
{
var bytesRead = await from.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0) break;
await to.WriteAsync(buffer, 0, bytesRead);
lock (requestLog)
{
requestLog.BytesTransferred += bytesRead;
}
if (_config.EnableVerboseLogging)
{
Console.WriteLine($"📡 数据转发 {direction}: {bytesRead} 字节");
}
}
}
catch (Exception ex)
{
if (_config.EnableVerboseLogging)
{
Console.WriteLine($"⚠️ 数据转发中断 {direction}: {ex.Message}");
}
}
}
/// <summary>
/// 检查域名是否被阻止
/// </summary>
private bool IsDomainBlocked(string host)
{
return _config.BlockedDomains.Any(blocked =>
host.Equals(blocked, StringComparison.OrdinalIgnoreCase) ||
host.EndsWith("." + blocked, StringComparison.OrdinalIgnoreCase));
}
/// <summary>
/// 发送阻止响应
/// </summary>
private async Task SendBlockedResponse(NetworkStream stream)
{
var response = "HTTP/1.1 403 Forbidden\r\n" +
"Content-Type: text/html\r\n" +
"Content-Length: 47\r\n" +
"\r\n" +
"<html><body><h1>Access Blocked</h1></body></html>";
var responseBytes = Encoding.UTF8.GetBytes(response);
await stream.WriteAsync(responseBytes, 0, responseBytes.Length);
}
/// <summary>
/// 更新域名统计
/// </summary>
private void UpdateDomainStats(RequestLog requestLog)
{
if (string.IsNullOrEmpty(requestLog.Host)) return;
_domainStats.AddOrUpdate(requestLog.Host,
new DomainStats
{
RequestCount = 1,
TotalBytes = requestLog.BytesTransferred,
LastAccess = requestLog.Timestamp
},
(key, existing) =>
{
existing.RequestCount++;
existing.TotalBytes += requestLog.BytesTransferred;
existing.LastAccess = requestLog.Timestamp;
return existing;
});
}
/// <summary>
/// 监控任务
/// </summary>
private async Task MonitoringTaskAsync()
{
while (_isRunning)
{
await Task.Delay(_config.MonitoringInterval);
if (_config.EnableMonitoring)
{
DisplayStatistics();
}
}
}
/// <summary>
/// 显示统计信息
/// </summary>
private void DisplayStatistics()
{
Console.WriteLine("\n" + "=".PadRight(60, '='));
Console.WriteLine("📊 代理服务器统计信息");
Console.WriteLine("=".PadRight(60, '='));
var now = DateTime.Now;
var recentLogs = _requestLogs.Where(log =>
(now - log.Timestamp).TotalMinutes <= _config.StatisticsTimeWindow).ToList();
Console.WriteLine($"🕒 统计时间窗口: {_config.StatisticsTimeWindow} 分钟");
Console.WriteLine($"📈 总请求数: {recentLogs.Count}");
Console.WriteLine($"✅ 成功请求: {recentLogs.Count(l => l.Status == "Completed")}");
Console.WriteLine($"❌ 失败请求: {recentLogs.Count(l => l.Status.StartsWith("Failed"))}");
Console.WriteLine($"🚫 阻止请求: {recentLogs.Count(l => l.Status == "Blocked")}");
if (recentLogs.Any())
{
Console.WriteLine($"📊 平均响应时间: {recentLogs.Average(l => l.Duration):F2} ms");
Console.WriteLine($"📦 总传输数据: {FormatBytes(recentLogs.Sum(l => l.BytesTransferred))}");
}
// 显示热门域名
var topDomains = _domainStats
.Where(kvp => (now - kvp.Value.LastAccess).TotalMinutes <= _config.StatisticsTimeWindow)
.OrderByDescending(kvp => kvp.Value.RequestCount)
.Take(5)
.ToList();
if (topDomains.Any())
{
Console.WriteLine("\n🔥 热门域名 (Top 5):");
foreach (var domain in topDomains)
{
Console.WriteLine($" {domain.Key}: {domain.Value.RequestCount} 次请求, {FormatBytes(domain.Value.TotalBytes)}");
}
}
Console.WriteLine("=".PadRight(60, '=') + "\n");
}
/// <summary>
/// 日志清理任务
/// </summary>
private async Task LogCleanupTaskAsync()
{
while (_isRunning)
{
await Task.Delay(_config.LogCleanupInterval);
var cutoffTime = DateTime.Now.AddHours(-_config.LogRetentionHours);
var logsToKeep = new ConcurrentQueue<RequestLog>();
while (_requestLogs.TryDequeue(out var log))
{
if (log.Timestamp > cutoffTime)
{
logsToKeep.Enqueue(log);
}
}
// 将保留的日志放回队列
while (logsToKeep.TryDequeue(out var log))
{
_requestLogs.Enqueue(log);
}
if (_config.EnableVerboseLogging)
{
Console.WriteLine($"🧹 日志清理完成,保留 {_requestLogs.Count} 条日志");
}
}
}
/// <summary>
/// 格式化字节数
/// </summary>
private string FormatBytes(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB" };
double len = bytes;
int order = 0;
while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len = len / 1024;
}
return $"{len:0.##} {sizes[order]}";
}
/// <summary>
/// 获取统计信息JSON
/// </summary>
public string GetStatisticsJson()
{
var now = DateTime.Now;
var recentLogs = _requestLogs.Where(log =>
(now - log.Timestamp).TotalMinutes <= _config.StatisticsTimeWindow).ToList();
var stats = new
{
Timestamp = now,
TimeWindow = _config.StatisticsTimeWindow,
TotalRequests = recentLogs.Count,
SuccessfulRequests = recentLogs.Count(l => l.Status == "Completed"),
FailedRequests = recentLogs.Count(l => l.Status.StartsWith("Failed")),
BlockedRequests = recentLogs.Count(l => l.Status == "Blocked"),
AverageResponseTime = recentLogs.Any() ? recentLogs.Average(l => l.Duration) : 0,
TotalBytesTransferred = recentLogs.Sum(l => l.BytesTransferred),
TopDomains = _domainStats
.Where(kvp => (now - kvp.Value.LastAccess).TotalMinutes <= _config.StatisticsTimeWindow)
.OrderByDescending(kvp => kvp.Value.RequestCount)
.Take(10)
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
};
return JsonSerializer.Serialize(stats, new JsonSerializerOptions { WriteIndented = true });
}
/// <summary>
/// 停止代理服务器
/// </summary>
public void Stop()
{
_isRunning = false;
_listener?.Stop();
Console.WriteLine("🛑 高级HTTP代理服务器已停止");
}
}
/// <summary>
/// 代理配置类
/// </summary>
publicclass ProxyConfig
{
publicbool EnableMonitoring { get; set; } = true;
publicbool EnableLogging { get; set; } = true;
publicbool EnableVerboseLogging { get; set; } = false;
publicbool EnableLogCleanup { get; set; } = true;
publicint MonitoringInterval { get; set; } = 30000; // 30秒
publicint StatisticsTimeWindow { get; set; } = 60; // 60分钟
publicint LogCleanupInterval { get; set; } = 3600000; // 1小时
publicint LogRetentionHours { get; set; } = 24; // 24小时
publicint ReceiveTimeout { get; set; } = 30000; // 30秒
publicint SendTimeout { get; set; } = 30000; // 30秒
public HashSet<string> BlockedDomains { get; set; } = new HashSet<string>();
}
/// <summary>
/// 请求日志记录
/// </summary>
publicclass RequestLog
{
public DateTime Timestamp { get; set; }
public DateTime EndTime { get; set; }
publicdouble Duration { get; set; }
publicstring ClientEndPoint { get; set; }
publicstring Method { get; set; }
publicstring Host { get; set; }
publicstring Url { get; set; }
publicint Port { get; set; }
publicstring Status { get; set; }
publiclong BytesTransferred { get; set; }
}
/// <summary>
/// 域名统计信息
/// </summary>
publicclass DomainStats
{
publicint RequestCount { get; set; }
publiclong TotalBytes { get; set; }
public DateTime LastAccess { get; set; }
}
/// <summary>
/// 请求信息数据结构
/// </summary>
publicclass RequestInfo
{
publicstring Method { get; set; }
publicstring Url { get; set; }
publicstring Version { get; set; }
publicstring Host { get; set; }
publicint Port { get; set; }
}
/// <summary>
/// 程序入口点
/// </summary>
class Program
{
static async Task Main(string[] args)
{
Console.OutputEncoding = Encoding.UTF8;
// 配置代理服务器
var config = new ProxyConfig
{
EnableMonitoring = true,
EnableLogging = true,
EnableVerboseLogging = false, // 设置为true可查看详细数据转发日志
MonitoringInterval = 30000, // 30秒显示一次统计
StatisticsTimeWindow = 60, // 统计过去60分钟的数据
// 添加一些被阻止的域名示例
BlockedDomains = new HashSet<string>
{
"malicious-site.com",
"blocked-domain.net"
}
};
var proxy = new AdvancedHttpProxyServer(8888, config);
// 设置控制台事件处理
Console.CancelKeyPress += (sender, e) =>
{
e.Cancel = true;
Console.WriteLine("\n正在停止服务器...");
proxy.Stop();
Environment.Exit(0);
};
// 启动额外的控制台命令处理
_ = Task.Run(() => HandleConsoleCommands(proxy));
// 启动代理服务器
await proxy.StartAsync();
}
/// <summary>
/// 处理控制台命令
/// </summary>
static async Task HandleConsoleCommands(AdvancedHttpProxyServer proxy)
{
Console.WriteLine("\n可用命令:");
Console.WriteLine(" stats - 显示当前统计信息");
Console.WriteLine(" json - 输出JSON格式统计信息");
Console.WriteLine(" quit - 退出程序");
Console.WriteLine("按 Ctrl+C 或输入 'quit' 停止服务器\n");
while (true)
{
try
{
var command = Console.ReadLine()?.Trim().ToLower();
switch (command)
{
case"stats":
// 这里可以调用显示统计的方法
Console.WriteLine("📊 手动请求统计信息显示");
break;
case"json":
Console.WriteLine(proxy.GetStatisticsJson());
break;
case"quit":
case"exit":
proxy.Stop();
Environment.Exit(0);
break;
case"help":
Console.WriteLine("可用命令: stats, json, quit, help");
break;
default:
if (!string.IsNullOrEmpty(command))
{
Console.WriteLine($"未知命令: {command}. 输入 'help' 查看可用命令");
}
break;
}
}
catch (Exception ex)
{
Console.WriteLine($"命令处理错误: {ex.Message}");
}
}
}
}
}
图片
实际应用场景
场景一:开发环境网络调试
// 启动代理服务器进行API调试
var proxy = new AdvancedHttpProxyServer(8888);
await proxy.StartAsync();
适用情况:
- 内网环境需要访问外部API
- 需要监控应用的网络请求
- 调试网络相关问题
场景二:企业网络管控
// 配置企业级代理,添加访问控制
var proxy = new AdvancedHttpProxyServer(3128);
proxy.AddBlockedDomain("social-media.com");
proxy.AddBlockedDomain("video-streaming.com");
await proxy.StartAsync();
适用情况:
- 企业内网访问控制
- 员工上网行为监控
- 恶意网站拦截
场景三:性能分析和优化
// 运行一段时间后导出分析数据
await proxy.ExportLogsAsync("network_analysis.json");
适用情况:
- 网络性能分析
- 用户行为分析
- 系统优化决策支持
高级技巧与最佳实践
性能优化建议
1. 连接池复用:对于频繁访问的域名,可以实现连接池
2. 缓存机制:缓存静态资源,减少重复请求
3. 异步处理:使用async/await确保高并发性能
4. 内存管理:定期清理请求日志,避免内存泄漏
安全性考虑
1. 访问控制:添加IP白名单/黑名单机制
2. SSL证书验证:确保HTTPS请求的安全性
3. 请求过滤:过滤恶意请求和攻击尝试
4. 日志保护:敏感信息脱敏处理
扩展性设计
1. 配置文件化:将设置项移到配置文件中
2. 插件架构:支持自定义请求处理插件
3. 集群部署:支持多实例负载均衡
4. 监控告警:集成监控系统,异常情况及时告警
总结
通过本文的学习,你已经掌握了:
三个核心要点
1. HTTP代理原理:理解了HTTP/HTTPS代理的工作机制和实现方式
2. C# 网络编程:学会了使用Socket和HttpClient进行网络通讯开发
3. 实战应用技巧:获得了可直接用于生产环境的代码模板和最佳实践
这套代理服务器不仅能解决日常开发中的网络访问问题,还能作为企业级应用的基础组件。记住,好的代码不仅要能运行,更要考虑性能、安全和可维护性!