C#使用HttpListener搭建本地web服务器如何为不同前缀返回不同响应
C# HttpListener 多路径响应与刷新bug修复
原有代码核心问题
- 执行顺序错误:先读取本地文件再获取请求上下文,返回内容永远是上一次请求时的旧数据
- 多余上下文消费:
ReloadPage方法额外调用HttpListener.GetContext()占用了下一次用户请求,直接导致需要刷新两次才能看到更新 - 无路由匹配逻辑:未对请求路径做判断,所有访问前缀返回相同内容
- 线程安全隐患:将
HttpListenerContext设为静态全局变量,多请求场景下会出现资源冲突
修复后完整代码
1. 服务器启动逻辑
private static Thread responseThread; // 全局静态HttpListener实例要先初始化 private static HttpListener HttpListener = new HttpListener(); public static void StartServer() { Console.WriteLine("Starting server..."); // 可以只加通用前缀,不需要逐个加路径前缀,后续通过路由判断即可 HttpListener.Prefixes.Add("http://localhost:5000/"); HttpListener.Start(); Console.WriteLine("Server started, access http://localhost:5000 to view data"); responseThread = new Thread(ResponseThread); responseThread.IsBackground = true; // 设为后台线程,程序退出时自动销毁 responseThread.Start(); }
2. 请求响应与路由逻辑
private static void ResponseThread() { const string jsonPath = @"C:\Users\Public\Documents\EchoStatsLogger\savedData.json"; while (HttpListener.IsListening) { // 先获取请求上下文 var context = HttpListener.GetContext(); try { // 禁用浏览器缓存,避免返回旧内容 context.Response.Headers.Add("Cache-Control", "no-cache, no-store, must-revalidate"); context.Response.Headers.Add("Pragma", "no-cache"); context.Response.Headers.Add("Expires", "0"); string responseContent = string.Empty; // 路由判断,根据不同路径返回不同内容 switch (context.Request.Url.AbsolutePath.ToLower()) { case "/home": // 返回自定义主页HTML responseContent = "<html><head><title>Home</title></head><body><h1>主页</h1><a href='/stats'>查看统计数据</a></body></html>"; context.Response.ContentType = "text/html; charset=utf-8"; break; case "/stats": // 返回统计页面 var jsonData = File.ReadAllText(jsonPath); responseContent = $"<html><head><title>Stats</title></head><body><h1>统计数据</h1><pre>{jsonData}</pre></body></html>"; context.Response.ContentType = "text/html; charset=utf-8"; break; default: // 根路径直接返回json数据 responseContent = File.ReadAllText(jsonPath); context.Response.ContentType = "application/json; charset=utf-8"; break; } var responseArray = Encoding.UTF8.GetBytes(responseContent); context.Response.OutputStream.Write(responseArray, 0, responseArray.Length); Console.WriteLine($"Request for {context.Request.Url.AbsolutePath} handled"); } catch (Exception ex) { context.Response.StatusCode = 500; var errorBytes = Encoding.UTF8.GetBytes($"Server error: {ex.Message}"); context.Response.OutputStream.Write(errorBytes, 0, errorBytes.Length); } finally { context.Response.KeepAlive = false; context.Response.Close(); } } }
修复说明
- 移除了逻辑错误的
ReloadPage方法,不需要额外重定向即可实现每次刷新返回最新数据 - 调整执行顺序为「先拿请求→再读最新文件→返回内容」,从根源解决刷新两次才更新的问题
- 新增了路径路由逻辑,可根据需求扩展不同路径的返回内容
- 增加了缓存禁用响应头,避免浏览器缓存旧内容
- 增加了异常捕获逻辑,避免单请求出错导致整个服务崩溃
内容的提问来源于stack exchange,提问作者gr1ffin
相关产品推荐
相关产品推荐

