刘东源 發表於 2026-1-8 08:27:55

基于C#编写一个HTTP服务器和客户端

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>实现思路</li><li>完整代码实现</li><li>关键代码解释</li><li>总结</li></ul></div><p>C# WinForm 程序中实现一个简易的 HTTP 服务器,能够处理 JSON 格式的 GET 和 POST 请求,这是一个很实用的需求,尤其适合做本地调试或轻量级服务。</p>
<p class="maodian"></p><h2>实现思路</h2>
<p>我会基于<code>.NET</code>自带的<code>HttpListener</code>类来实现这个 HTTP 服务器,它可以让 WinForm 程序监听指定端口并处理 HTTP 请求。核心步骤包括:</p>
<ul><li>1、初始化<code>HttpListener</code>并配置监听地址</li><li>2、异步监听并处理客户端请求</li><li>3、区分 GET/POST 请求类型</li><li>4、解析 / 响应 JSON 格式数据</li><li>5、在 WinForm 界面中控制服务器的启动和停止</li></ul>
<p class="maodian"></p><h2>完整代码实现</h2>
<p>以下是一个开箱即用的 WinForm 程序代码,包含 UI 交互和完整的 HTTP 服务逻辑:</p>
<p>1. 首先是 Form1 的设计(Form1.Designer.cs 核心部分)</p>
<div class="jb51code"><pre class="brush:csharp;">using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace HttpServerWinFormClient
{
    public partial class Form1 : Form
    {
      private readonly HttpClient _httpClient;
      // 默认服务器地址
      private string _baseUrl = "http://localhost:8080/";
      public Form1()
      {
            InitializeComponent();
            // 初始化HttpClient(设置超时10秒)
            _httpClient = new HttpClient { Timeout = TimeSpan.FromSeconds(10) };

            // 初始化界面
            txtServerUrl.Text = _baseUrl;
            cbxMethod.SelectedIndex = 0; // 默认GET
            // 预设JSON模板
            txtRequestJson.Text = @"
{
    ""Id"": 1001,
    ""Name"": ""张三-测试中文"",
    ""Email"": ""zhangsan@test.com""
}";
            // 清空响应区
            ClearResponse();
      }
      #region 界面事件
      /// &lt;summary&gt;
      /// 发送请求按钮点击
      /// &lt;/summary&gt;
      private async void btnSend_Click(object sender, EventArgs e)
      {
            try
            {
                // 禁用按钮,防止重复点击
                btnSend.Enabled = false;
                ClearResponse();
                _baseUrl = txtServerUrl.Text.Trim();
                if (string.IsNullOrWhiteSpace(_baseUrl))
                {
                  AppendLog("错误:服务器地址不能为空!", LogLevel.Error);
                  btnSend.Enabled = true;
                  return;
                }
                // 记录开始时间
                var stopwatch = System.Diagnostics.Stopwatch.StartNew();
                AppendLog($"开始发送{cbxMethod.Text}请求到:{_baseUrl}", LogLevel.Info);
                HttpResponseMessage response = null;
                if (cbxMethod.Text == "GET")
                {
                  // 发送GET请求
                  response = await _httpClient.GetAsync(_baseUrl);
                }
                else if (cbxMethod.Text == "POST")
                {
                  // 验证POST请求体
                  string json = txtRequestJson.Text.Trim();
                  if (string.IsNullOrWhiteSpace(json))
                  {
                        AppendLog("错误:POST请求体不能为空!", LogLevel.Error);
                        btnSend.Enabled = true;
                        return;
                  }
                  // 构造POST内容(UTF-8编码)
                  var content = new StringContent(json, Encoding.UTF8, "application/json");
                  content.Headers.TryAddWithoutValidation("Content-Type", "application/json; charset=utf-8");
                  // 发送POST请求
                  response = await _httpClient.PostAsync(_baseUrl, content);
                }
                // 停止计时
                stopwatch.Stop();
                // 解析响应
                string responseContent = await response.Content.ReadAsStringAsync();
                // 显示响应信息
                lblStatusCode.Text = $"状态码:{(int)response.StatusCode} ({response.StatusCode})";
                lblTimeCost.Text = $"耗时:{stopwatch.ElapsedMilliseconds} ms";
                txtResponseJson.Text = FormatJson(responseContent);
                // 记录日志
                AppendLog($"请求完成 - 状态码:{(int)response.StatusCode},耗时:{stopwatch.ElapsedMilliseconds}ms", LogLevel.Success);
            }
            catch (HttpRequestException ex)
            {
                AppendLog($"请求异常:{ex.Message}(请检查服务器是否启动/地址是否正确)", LogLevel.Error);
            }
            catch (TaskCanceledException)
            {
                AppendLog("请求超时:服务器无响应(超时10秒)", LogLevel.Error);
            }
            catch (Exception ex)
            {
                AppendLog($"未知异常:{ex.Message}", LogLevel.Error);
            }
            finally
            {
                btnSend.Enabled = true;
            }
      }
      /// &lt;summary&gt;
      /// 清空响应按钮
      /// &lt;/summary&gt;
      private void btnClear_Click(object sender, EventArgs e)
      {
            ClearResponse();
            txtLog.Clear();
      }
      /// &lt;summary&gt;
      /// 快速测试:正常POST(含中文)
      /// &lt;/summary&gt;
      private void btnTestNormalPost_Click(object sender, EventArgs e)
      {
            cbxMethod.SelectedIndex = 1; // 切换到POST
            txtRequestJson.Text = @"
{
    ""Id"": 1001,
    ""Name"": ""张三-测试中文"",
    ""Email"": ""zhangsan@test.com""
}";
            AppendLog("已加载【正常POST(含中文)】测试模板", LogLevel.Info);
      }
      /// &lt;summary&gt;
      /// 快速测试:错误JSON(Id为字符串)
      /// &lt;/summary&gt;
      private void btnTestErrorPost_Click(object sender, EventArgs e)
      {
            cbxMethod.SelectedIndex = 1; // 切换到POST
            txtRequestJson.Text = @"
{
    ""Id"": ""1001a"",
    ""Name"": ""李四"",
    ""Email"": ""lisi@test.com""
}";
            AppendLog("已加载【错误JSON(Id为字符串)】测试模板", LogLevel.Info);
      }
      /// &lt;summary&gt;
      /// 请求方法切换(隐藏/显示POST请求体)
      /// &lt;/summary&gt;
      private void cbxMethod_SelectedIndexChanged(object sender, EventArgs e)
      {
            // GET隐藏请求体,POST显示
            panelPostJson.Visible = (cbxMethod.Text == "POST");
      }
      #endregion
      #region 辅助方法
      /// &lt;summary&gt;
      /// 清空响应区域
      /// &lt;/summary&gt;
      private void ClearResponse()
      {
            lblStatusCode.Text = "状态码:-";
            lblTimeCost.Text = "耗时:- ms";
            txtResponseJson.Clear();
      }
      /// &lt;summary&gt;
      /// 格式化JSON字符串(便于阅读)
      /// &lt;/summary&gt;
      private string FormatJson(string json)
      {
            if (string.IsNullOrWhiteSpace(json)) return "";
            try
            {
                // 使用Newtonsoft.Json格式化(需安装NuGet包)
                dynamic parsedJson = Newtonsoft.Json.JsonConvert.DeserializeObject(json);
                return Newtonsoft.Json.JsonConvert.SerializeObject(parsedJson, Newtonsoft.Json.Formatting.Indented);
            }
            catch
            {
                // 格式化失败则返回原字符串
                return json;
            }
      }
      /// &lt;summary&gt;
      /// 日志级别枚举
      /// &lt;/summary&gt;
      private enum LogLevel
      {
            Info,
            Success,
            Error
      }
      /// &lt;summary&gt;
      /// 追加日志(线程安全)
      /// &lt;/summary&gt;
      private void AppendLog(string message, LogLevel level = LogLevel.Info)
      {
            if (txtLog.InvokeRequired)
            {
                txtLog.Invoke(new Action&lt;string, LogLevel&gt;(AppendLog), message, level);
                return;
            }
            string timeStr = $"[{DateTime.Now:HH:mm:ss.fff}]";
            string levelStr = level switch
            {
                LogLevel.Info =&gt; "[信息]",
                LogLevel.Success =&gt; "[成功]",
                LogLevel.Error =&gt; "[错误]",
                _ =&gt; "[未知]"
            };
            string logLine = $"{timeStr} {levelStr} {message}{Environment.NewLine}";
            txtLog.AppendText(logLine);
            // 自动滚动到最后一行
            txtLog.SelectionStart = txtLog.TextLength;
            txtLog.ScrollToCaret();
      }
      #endregion
      #region 窗体设计器代码(自动生成)
      private System.ComponentModel.IContainer components = null;
      private TextBox txtServerUrl;
      private Label label1;
      private ComboBox cbxMethod;
      private Button btnSend;
      private Panel panelPostJson;
      private Label label2;
      private TextBox txtRequestJson;
      private Label label3;
      private TextBox txtResponseJson;
      private Label lblStatusCode;
      private Label lblTimeCost;
      private Button btnClear;
      private GroupBox groupBox1;
      private GroupBox groupBox2;
      private GroupBox groupBox3;
      private TextBox txtLog;
      private Button btnTestNormalPost;
      private Button btnTestErrorPost;
      protected override void Dispose(bool disposing)
      {
            if (disposing &amp;&amp; (components != null))
            {
                components.Dispose();
            }
            _httpClient?.Dispose();
            base.Dispose(disposing);
      }
      private void InitializeComponent()
      {
            this.txtServerUrl = new System.Windows.Forms.TextBox();
            this.label1 = new System.Windows.Forms.Label();
            this.cbxMethod = new System.Windows.Forms.ComboBox();
            this.btnSend = new System.Windows.Forms.Button();
            this.panelPostJson = new System.Windows.Forms.Panel();
            this.txtRequestJson = new System.Windows.Forms.TextBox();
            this.label2 = new System.Windows.Forms.Label();
            this.label3 = new System.Windows.Forms.Label();
            this.txtResponseJson = new System.Windows.Forms.TextBox();
            this.lblStatusCode = new System.Windows.Forms.Label();
            this.lblTimeCost = new System.Windows.Forms.Label();
            this.btnClear = new System.Windows.Forms.Button();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.btnTestErrorPost = new System.Windows.Forms.Button();
            this.btnTestNormalPost = new System.Windows.Forms.Button();
            this.groupBox2 = new System.Windows.Forms.GroupBox();
            this.groupBox3 = new System.Windows.Forms.GroupBox();
            this.txtLog = new System.Windows.Forms.TextBox();
            this.panelPostJson.SuspendLayout();
            this.groupBox1.SuspendLayout();
            this.groupBox2.SuspendLayout();
            this.groupBox3.SuspendLayout();
            this.SuspendLayout();
            // txtServerUrl
            this.txtServerUrl.Location = new System.Drawing.Point(85, 15);
            this.txtServerUrl.Name = "txtServerUrl";
            this.txtServerUrl.Size = new System.Drawing.Size(250, 23);
            this.txtServerUrl.TabIndex = 0;
            // label1
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(10, 18);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(69, 17);
            this.label1.TabIndex = 1;
            this.label1.Text = "服务器地址:";
            // cbxMethod
            this.cbxMethod.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
            this.cbxMethod.Items.AddRange(new object[] { "GET", "POST" });
            this.cbxMethod.Location = new System.Drawing.Point(341, 15);
            this.cbxMethod.Name = "cbxMethod";
            this.cbxMethod.Size = new System.Drawing.Size(80, 25);
            this.cbxMethod.TabIndex = 2;
            this.cbxMethod.SelectedIndexChanged += new System.EventHandler(this.cbxMethod_SelectedIndexChanged);
            // btnSend
            this.btnSend.Location = new System.Drawing.Point(427, 15);
            this.btnSend.Name = "btnSend";
            this.btnSend.Size = new System.Drawing.Size(80, 25);
            this.btnSend.TabIndex = 3;
            this.btnSend.Text = "发送请求";
            this.btnSend.UseVisualStyleBackColor = true;
            this.btnSend.Click += new System.EventHandler(this.btnSend_Click);
            // panelPostJson
            this.panelPostJson.Controls.Add(this.txtRequestJson);
            this.panelPostJson.Controls.Add(this.label2);
            this.panelPostJson.Location = new System.Drawing.Point(10, 45);
            this.panelPostJson.Name = "panelPostJson";
            this.panelPostJson.Size = new System.Drawing.Size(497, 120);
            this.panelPostJson.TabIndex = 4;
            // txtRequestJson
            this.txtRequestJson.Dock = System.Windows.Forms.DockStyle.Fill;
            this.txtRequestJson.Multiline = true;
            this.txtRequestJson.Name = "txtRequestJson";
            this.txtRequestJson.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
            this.txtRequestJson.Size = new System.Drawing.Size(497, 95);
            this.txtRequestJson.TabIndex = 1;
            // label2
            this.label2.AutoSize = true;
            this.label2.Location = new System.Drawing.Point(0, 0);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(79, 17);
            this.label2.TabIndex = 0;
            this.label2.Text = "POST请求体:";
            // label3
            this.label3.AutoSize = true;
            this.label3.Location = new System.Drawing.Point(10, 170);
            this.label3.Name = "label3";
            this.label3.Size = new System.Drawing.Size(79, 17);
            this.label3.TabIndex = 5;
            this.label3.Text = "响应内容:";
            // txtResponseJson
            this.txtResponseJson.Location = new System.Drawing.Point(10, 190);
            this.txtResponseJson.Multiline = true;
            this.txtResponseJson.Name = "txtResponseJson";
            this.txtResponseJson.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
            this.txtResponseJson.Size = new System.Drawing.Size(497, 120);
            this.txtResponseJson.TabIndex = 6;
            // lblStatusCode
            this.lblStatusCode.AutoSize = true;
            this.lblStatusCode.Location = new System.Drawing.Point(10, 315);
            this.lblStatusCode.Name = "lblStatusCode";
            this.lblStatusCode.Size = new System.Drawing.Size(53, 17);
            this.lblStatusCode.TabIndex = 7;
            this.lblStatusCode.Text = "状态码:-";
            // lblTimeCost
            this.lblTimeCost.AutoSize = true;
            this.lblTimeCost.Location = new System.Drawing.Point(120, 315);
            this.lblTimeCost.Name = "lblTimeCost";
            this.lblTimeCost.Size = new System.Drawing.Size(65, 17);
            this.lblTimeCost.TabIndex = 8;
            this.lblTimeCost.Text = "耗时:- ms";
            // btnClear
            this.btnClear.Location = new System.Drawing.Point(427, 310);
            this.btnClear.Name = "btnClear";
            this.btnClear.Size = new System.Drawing.Size(80, 25);
            this.btnClear.TabIndex = 9;
            this.btnClear.Text = "清空";
            this.btnClear.UseVisualStyleBackColor = true;
            this.btnClear.Click += new System.EventHandler(this.btnClear_Click);
            // groupBox1
            this.groupBox1.Controls.Add(this.btnTestErrorPost);
            this.groupBox1.Controls.Add(this.btnTestNormalPost);
            this.groupBox1.Controls.Add(this.txtServerUrl);
            this.groupBox1.Controls.Add(this.label1);
            this.groupBox1.Controls.Add(this.cbxMethod);
            this.groupBox1.Controls.Add(this.btnSend);
            this.groupBox1.Controls.Add(this.panelPostJson);
            this.groupBox1.Location = new System.Drawing.Point(10, 10);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(517, 180);
            this.groupBox1.TabIndex = 10;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "请求配置";
            // btnTestNormalPost
            this.btnTestNormalPost.Location = new System.Drawing.Point(10, 170);
            this.btnTestNormalPost.Name = "btnTestNormalPost";
            this.btnTestNormalPost.Size = new System.Drawing.Size(150, 25);
            this.btnTestNormalPost.TabIndex = 5;
            this.btnTestNormalPost.Text = "快速测试:正常POST(中文)";
            this.btnTestNormalPost.UseVisualStyleBackColor = true;
            this.btnTestNormalPost.Click += new System.EventHandler(this.btnTestNormalPost_Click);
            // btnTestErrorPost
            this.btnTestErrorPost.Location = new System.Drawing.Point(166, 170);
            this.btnTestErrorPost.Name = "btnTestErrorPost";
            this.btnTestErrorPost.Size = new System.Drawing.Size(150, 25);
            this.btnTestErrorPost.TabIndex = 6;
            this.btnTestErrorPost.Text = "快速测试:错误JSON(Id字符串)";
            this.btnTestErrorPost.UseVisualStyleBackColor = true;
            this.btnTestErrorPost.Click += new System.EventHandler(this.btnTestErrorPost_Click);
            // groupBox2
            this.groupBox2.Controls.Add(this.label3);
            this.groupBox2.Controls.Add(this.txtResponseJson);
            this.groupBox2.Controls.Add(this.lblStatusCode);
            this.groupBox2.Controls.Add(this.lblTimeCost);
            this.groupBox2.Controls.Add(this.btnClear);
            this.groupBox2.Location = new System.Drawing.Point(10, 195);
            this.groupBox2.Name = "groupBox2";
            this.groupBox2.Size = new System.Drawing.Size(517, 340);
            this.groupBox2.TabIndex = 11;
            this.groupBox2.TabStop = false;
            this.groupBox2.Text = "响应结果";
            // groupBox3
            this.groupBox3.Controls.Add(this.txtLog);
            this.groupBox3.Location = new System.Drawing.Point(10, 540);
            this.groupBox3.Name = "groupBox3";
            this.groupBox3.Size = new System.Drawing.Size(517, 150);
            this.groupBox3.TabIndex = 12;
            this.groupBox3.TabStop = false;
            this.groupBox3.Text = "操作日志";
            // txtLog
            this.txtLog.Dock = System.Windows.Forms.DockStyle.Fill;
            this.txtLog.Multiline = true;
            this.txtLog.Name = "txtLog";
            this.txtLog.ReadOnly = true;
            this.txtLog.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
            this.txtLog.Size = new System.Drawing.Size(517, 125);
            this.txtLog.TabIndex = 0;
            // Form1
            this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(539, 700);
            this.Controls.Add(this.groupBox3);
            this.Controls.Add(this.groupBox2);
            this.Controls.Add(this.groupBox1);
            this.Name = "Form1";
            this.Text = "HTTP服务器测试客户端";
            this.panelPostJson.ResumeLayout(false);
            this.panelPostJson.PerformLayout();
            this.groupBox1.ResumeLayout(false);
            this.groupBox1.PerformLayout();
            this.groupBox2.ResumeLayout(false);
            this.groupBox2.PerformLayout();
            this.groupBox3.ResumeLayout(false);
            this.groupBox3.PerformLayout();
            this.ResumeLayout(false);
      }
      #endregion
    }
}</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202601/2026010808272488.jpg" /></p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202601/2026010808272439.png" /></p>
<p>APIPost软件测试:</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202601/2026010808272415.png" /></p>
<p class="maodian"></p><h2>关键代码解释</h2>
<p><strong>1、HttpListener</strong></p>
<p>:核心类,用于监听 HTTP 请求,支持多前缀、多请求处理</p>
<p><strong>2、多线程处理</strong></p>
<p>:监听线程和请求处理线程分离,避免阻塞 UI 线程</p>
<p><strong>3、JSON 序列化 / 反序列化</strong></p>
<p>:使用<code>JavaScriptSerializer</code>处理 JSON 数据(也可以替换为 Newtonsoft.Json,更推荐)</p>
<p><strong>4、跨线程 UI 更新</strong></p>
<p>:通过<code>Control.Invoke</code>实现日志的跨线程输出,避免 WinForm 跨线程访问异常</p>
<p><strong>5、异常处理</strong></p>
<p>:完善的异常捕获和错误响应,保证服务器稳定运行</p>
<p class="maodian"></p><h2>总结</h2>
<p>1、该 WinForm 服务器基于<code>HttpListener</code>实现,能够稳定处理 JSON 格式的 GET/POST 请求,核心是<strong>异步监听 + 多线程处理请求</strong>,避免阻塞 UI。</p>
<p>2、关键要点:需要管理员权限运行、正确处理跨线程 UI 更新、严格遵循 HTTP 响应规范(设置 Content-Type、关闭响应流)。</p>
<p>到此这篇关于基于C#编写一个HTTP服务器和客户端的文章就介绍到这了,更多相关C# HTTP服务器和客户端内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>C# http系列之以form-data方式上传多个文件及键值对集合到远程服务器</li><li>基于C#实现一个最简单的HTTP服务器实例</li><li>C#实现HTTP协议迷你服务器(两种方法)</li><li>c# HttpWebRequest通过代理服务器抓取网页内容应用介绍</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: 基于C#编写一个HTTP服务器和客户端