最近在做的一个项目,是一个web项目,需要从服务端主动推送数据到客户端,其实有很多实现方式,但是选择了一种实现起来相对简单的就是使用 EventSource 来实现,实现起来也很简单,参考了网络上的一些实现方法。实现以后测试发现一些问题,采用IISExpress 作为服务器,客户端能接受到服务端推送的消息,并且刷新客户端以后,还能继续接收,但是如果换成IIS服务器,则第一次能够访问,刷新以后,客户端状态一直出来pending状态,查看记得的日志,在IIS服务器中,如果是刷新请求的话,服务器报错:远程主机关闭连接,错误代码:0x800704cd。
下面是我的服务端实现代码,麻烦各位园友帮忙看看。感谢感谢。
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Linq; using System.Net.Http; using System.Threading; using System.Web.Http; using Harrenhal.Merchant.Utility; using StackExchange.Redis; using StackExchange.Redis.Extensions.Core; using StackExchange.Redis.Extensions.Newtonsoft; using Sylvanas.Logging; using Sylvanas.Logging.Extensions; namespace Harrenhal.Merchant.Controllers { [RoutePrefix("api/event")] public class EventController : ApiController { private static readonly ILogger Logger = LoggerCache.GetLogger(typeof(EventController)); private static readonly string DispatchSuccessEventPrefix = "DispatchSuccess"; private static Timer _timer = default(Timer); private static readonly ConcurrentDictionary<string, StreamWriter> StreamWriters = new ConcurrentDictionary<string, StreamWriter>(); public EventController() { _timer = _timer ?? new Timer(TimerCallback, null, 0, 1000); } public HttpResponseMessage Get(string userid) { var response = Request.CreateResponse(); response.Content = new PushStreamContent( (stream, httpContent, transportContext) => { var writer = new StreamWriter(stream); StreamWriters.TryAdd(userid, writer); }, "text/event-stream"); return response; } private static void TimerCallback(object state) { _timer.Change(Timeout.Infinite, Timeout.Infinite); try { foreach (var streamWriter in StreamWriters) { //ConnectionMultiplexer connectionMultiplexer = // RedisUtility.GetConnection( // ConfigurationManager.ConnectionStrings["My.Redis.Cache"].ConnectionString); //var client = new StackExchangeRedisCacheClient(connectionMultiplexer, // new NewtonsoftSerializer()); //var key = // client.SearchKeys($"{GetLocalizedKey(DispatchSuccessEventPrefix, streamWriter.Key)}*") // .FirstOrDefault(); //var writer = streamWriter.Value; //if (key != null) //{ // Logger.Error($"key:{key}"); // var database = connectionMultiplexer.GetDatabase(); // var message = database.StringGet(key); // Logger.Error($"message:{message}"); // if (!message.IsNullOrEmpty) // { // database.KeyDelete(key); // writer.WriteLine("data:" + message + "\n"); // } // else // { // writer.WriteLine("data:" + "\n"); // } //} //else //{ // writer.WriteLine("data:" + "\n"); //} //writer.Flush(); } } catch (Exception ex) { Logger.Error(ex, "获取通知消息失败"); } finally { _timer.Change(1000, 1000); } } private static string GetLocalizedKey(string prefix, string key) { return prefix + ":Cache:" + key; } } }
你刷新了,之前的服务端对你客户端发送响应的就断了,当然会报那个错。
webapi没怎么用过,你看下Response中还有没有一个IsClientConnected的属性,用于判断客户端是否还连着在。
但是在IISExpress 中就不会出现这种情况,可以刷新