长轮询
我们知道, HTTP 请求发出后,⼀般会给服务器留⼀定的时间做响应,⽐如 3 秒,规定时间内没返回,就 认为是超时。 如果我们的 HTTP 请求将超时设置的很⼤,⽐如 30 秒, 在这 30 秒内只要服务器收到了扫码请求,就⽴⻢ 返回给客户端⽹⻚。如果超时,那就⽴⻢发起下⼀次请求。 这样就减少了 HTTP 请求的个数,并且由于⼤部分情况下,⽤户都会在某个 30 秒的区间内做扫码操作, 所以响应也是及时的。 using Microsoft.AspNetCore.Mvc; using System.Threading; [ApiController] [Route("api/[controller]")] public class LongPollingController : ControllerBase { private static List<string> _messages = new List<string>(); private static int _lastMessageId = 0; private static object _lockObject = new object(); // 发送消息的端点 [HttpPost("send")] public IActionResult SendMessage([FromBody] MessageRequest request) { lock (_lockObject) { _messages.Add(request.Message); _lastMessageId++; } return Ok(new { Status = "Message sent" }); } // 长轮询接收消息的端点 [HttpGet("receive")] public async Task<IActionResult> ReceiveMessages(int lastId = -1, int timeoutSeconds = 30) { var startTime = DateTime.UtcNow; var endTime = startTime.AddSeconds(timeoutSeconds); while (DateTime.UtcNow < endTime) { List<string> newMessages; int currentLastId; lock (_lockObject) { currentLastId = _lastMessageId; newMessages = _messages.Skip(lastId + 1).ToList(); } // 如果有新消息,立即返回 if (newMessages.Count > 0) { return Ok(new { Messages = newMessages, LastId = currentLastId }); } // 等待一小段时间后再检查 await Task.Delay(500); } // 超时返回空结果 return Ok(new { Messages = new string[0], LastId = _lastMessageId }); } } public class MessageRequest { public string Message { get; set; } } 实现原理说明 服务端: 维护一个消息队列和最后消息ID 接收消息端点用于添加新消息到队列 长轮询端点循环检查是否有新消息,如果有则立即返回,否则等待一段时间继续检查直到超时 ...