十分钟搞定C# HTTP代理服务器:从原理到实战的完全指南

服务器 服务器产品
据不完全统计,超过70%的企业级应用都需要代理服务器来处理网络请求,但市面上的代理工具要么功能单一,要么配置复杂。今天就带你用C#从零开始,10分钟内搭建一个功能完整的HTTP代理服务器,让你彻底掌握网络代理的核心原理和实现技巧!

你是否遇到过这样的开发痛点:内网环境无法访问外部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. 实战应用技巧:获得了可直接用于生产环境的代码模板和最佳实践

这套代理服务器不仅能解决日常开发中的网络访问问题,还能作为企业级应用的基础组件。记住,好的代码不仅要能运行,更要考虑性能、安全和可维护性

责任编辑:武晓燕 来源: 技术老小子
相关推荐

2023-04-12 11:18:51

甘特图前端

2023-11-30 10:21:48

虚拟列表虚拟列表工具库

2023-12-08 13:19:00

前端Reactour流行库

2019-09-16 09:14:51

2016-06-13 14:07:50

Java动态代理

2009-10-10 15:50:25

2020-12-17 06:48:21

SQLkafkaMySQL

2019-04-01 14:59:56

负载均衡服务器网络

2023-06-07 08:27:10

Docker容器

2023-12-11 13:05:21

2023-03-13 07:52:13

2021-03-03 11:36:57

Java 8Java 15Java

2020-09-27 14:41:37

C语言编程语言计算机

2022-03-23 09:32:38

微服务容器Kubernetes

2022-06-16 07:31:41

Web组件封装HTML 标签

2021-09-07 09:40:20

Spark大数据引擎

2024-06-19 09:58:29

2023-12-13 13:26:41

2023-12-21 11:39:47

2012-07-10 01:22:32

PythonPython教程
点赞
收藏

51CTO技术栈公众号