# WinForm 程序中实现一个简易的 HTTP 服务器,能够处理 JSON 格式的 GET 和 POST 请求,这是一个很实用的需求,尤其适合做本地调试或轻量级服务。

实现思路

我会基于.NET自带的HttpListener类来实现这个 HTTP 服务器,它可以让 WinForm 程序监听指定端口并处理 HTTP 请求。核心步骤包括:

  • 1、初始化HttpListener并配置监听地址
  • 2、异步监听并处理客户端请求
  • 3、区分 GET/POST 请求类型
  • 4、解析 / 响应 JSON 格式数据
  • 5、在 WinForm 界面中控制服务器的启动和停止

完整代码实现

以下是一个开箱即用的 WinForm 程序代码,包含 UI 交互和完整的 HTTP 服务逻辑:

1. 首先是 Form1 的设计(Form1.Designer.cs 核心部分)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

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 界面事件

        /// <summary>

        /// 发送请求按钮点击

        /// </summary>

        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;

            }

        }

        /// <summary>

        /// 清空响应按钮

        /// </summary>

        private void btnClear_Click(object sender, EventArgs e)

        {

            ClearResponse();

            txtLog.Clear();

        }

        /// <summary>

        /// 快速测试:正常POST(含中文)

        /// </summary>

        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);

        }

        /// <summary>

        /// 快速测试:错误JSON(Id为字符串)

        /// </summary>

        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);

        }

        /// <summary>

        /// 请求方法切换(隐藏/显示POST请求体)

        /// </summary>

        private void cbxMethod_SelectedIndexChanged(object sender, EventArgs e)

        {

            // GET隐藏请求体,POST显示

            panelPostJson.Visible = (cbxMethod.Text == "POST");

        }

        #endregion

        #region 辅助方法

        /// <summary>

        /// 清空响应区域

        /// </summary>

        private void ClearResponse()

        {

            lblStatusCode.Text = "状态码:-";

            lblTimeCost.Text = "耗时:- ms";

            txtResponseJson.Clear();

        }

        /// <summary>

        /// 格式化JSON字符串(便于阅读)

        /// </summary>

        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;

            }

        }

        /// <summary>

        /// 日志级别枚举

        /// </summary>

        private enum LogLevel

        {

            Info,

            Success,

            Error

        }

        /// <summary>

        /// 追加日志(线程安全)

        /// </summary>

        private void AppendLog(string message, LogLevel level = LogLevel.Info)

        {

            if (txtLog.InvokeRequired)

            {

                txtLog.Invoke(new Action<string, LogLevel>(AppendLog), message, level);

                return;

            }

            string timeStr = $"[{DateTime.Now:HH:mm:ss.fff}]";

            string levelStr = level switch

            {

                LogLevel.Info => "[信息]",

                LogLevel.Success => "[成功]",

                LogLevel.Error => "[错误]",

                _ => "[未知]"

            };

            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 && (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

    }

}

APIPost软件测试:

关键代码解释

1、HttpListener

:核心类,用于监听 HTTP 请求,支持多前缀、多请求处理

2、多线程处理

:监听线程和请求处理线程分离,避免阻塞 UI 线程

3、JSON 序列化 / 反序列化

:使用JavaScriptSerializer处理 JSON 数据(也可以替换为 Newtonsoft.Json,更推荐)

4、跨线程 UI 更新

:通过Control.Invoke实现日志的跨线程输出,避免 WinForm 跨线程访问异常

5、异常处理

:完善的异常捕获和错误响应,保证服务器稳定运行

总结

1、该 WinForm 服务器基于HttpListener实现,能够稳定处理 JSON 格式的 GET/POST 请求,核心是异步监听 + 多线程处理请求,避免阻塞 UI。2、关键要点:需要管理员权限运行、正确处理跨线程 UI 更新、严格遵循 HTTP 响应规范(设置 Content-Type、关闭响应流)。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐