【问题标题】:HTML5 EventSource onmessage never called from Web API 2HTML5 EventSource onmessage 从未从 Web API 2 调用
【发布时间】:2014-08-19 02:22:50
【问题描述】:

我有一个 RESTful Web API 2 解决方案,其方法是从 AngularJS 应用程序调用的。我想添加对从服务器端 API 向客户端逻辑发送通知的支持。但是,通过调用 Javascript 中的 addEventListener 设置的消息和打开方法永远不会被调用。 Web API 控制器如下:

namespace Controllers
{
    public class EventController : ApiController
    {
        private static readonly List<StreamWriter> ConnectedClients = new List<StreamWriter>();
        private static Timer _timer;

        public EventController()
        {
            if(_timer == null)
                _timer = new Timer(TimerCallback, null, 0, 2000);
        }

        public static void OnStreamAvailable(Stream stream, HttpContent headers, TransportContext context)
        {
            var streamwriter = new StreamWriter(stream);
            ConnectedClients.Add(streamwriter);
        }

        private static void MessageCallback(Message m)
        {
            foreach (var subscriber in ConnectedClients)
            {
                try
                {
                    subscriber.Write("data: {0}\n\n", JsonConvert.SerializeObject(m));
                    subscriber.Flush();
                }
                catch (Exception ex)
                {
                    // This probably means the user has disconnected
                    ConnectedClients.Remove(subscriber);
                }
            }
        }

        private static void TimerCallback(object state)
        {
            var m = new Message
            {
                Date = DateTime.Now.ToUniversalTime().ToString("u"),
                Text = "Hello World!"
            };
            MessageCallback(m);
        }

        [HttpGet]
        public HttpResponseMessage Get(HttpRequestMessage request)
        {
            // New subscription request
            var response = request.CreateResponse();
            response.Headers.Add("Access-Control-Allow-Origin", "*");
            response.Headers.Add("Cache-Control", "no-cache, must-revalidate");
            response.Content = new PushStreamContent((Action<Stream, HttpContent, TransportContext>)OnStreamAvailable, "text/event-stream");
            return response;
        }
    }
}

请注意,我还为我的 HttpGet 方法尝试了以下方法:

public HttpResponseMessage Get()
{
    // New subscription request
    var response = Request.CreateResponse();
    response.Headers.Add("Access-Control-Allow-Origin", "*");
    response.Headers.Add("Cache-Control", "no-cache, must-revalidate");
    response.Content = new PushStreamContent((Action<Stream, HttpContent, TransportContext>)OnStreamAvailable, "text/event-stream");
    return response;
}

Javascript:

if (!!window.EventSource) {
    var eventSource = new EventSource(GlobalConfig.apiRoot + 'Event');

    eventSource.addEventListener('open', function (e) {
        console.log("open");
    }, false);

    eventSource.addEventListener('error', function (e) {
        console.log("error");
    }, false);

    eventSource.addEventListener('message', function (e) {
        console.log('message');
    }, false);

} else {
    // not supported!
}

我在 Visual Studio 2013 下通过 IISExpress 运行它。但是我也在 IIS 8 下进行了测试,结果相同。所有测试均在 Google Chrome 版本 36.0.1985.143 m 中完成。我可以验证的是:

  1. 调用 Web API 中的 Get 方法。
  2. 计时器(我设置它只是为了测试)按预期运行并调用 TimerCallback 方法。然后运行 ​​MessageCallback。
  3. 如果我用 Chrome 关闭 Visual Studio/IISExpress 打开 Javascript 中的错误方法,则会调用 net::ERR_CONNECTION_REFUSED 错误。
  4. 类似地,如果我使用运行 Visual Studio/IISExpress 的浏览器关闭了 MessageCallback 控制器方法中的 HttpException。

也就是说,似乎确实存在某种联系,但我无法弄清楚为什么在 Javascript 中从未调用消息和打开处理程序。

为了检查 AngularJS 中的任何内容是否可能影响我将 Javascript 移动到静态 HTML 页面。在 Chrome 控制台中记录了以下内容:

Request URL:http://localhost/.../api/Event
Request Headers
Provisional headers are shown
Accept:text/event-stream
Cache-Control:no-cache
Referer:http://localhost/.../test.html
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)    Chrome/36.0.1985.143 Safari/537.36

请求的状态始终为“待处理”。但是,鉴于连接保持打开状态,这是我所期望的。

我们将不胜感激地收到有关获得此功能的任何建议。

【问题讨论】:

  • 好的,这确实在 IIS 8 下运行,但请求返回最多可能需要 2 分钟。然后将所有消息转储回客户端。我更改了计时器,因此它在 HttpGet 方法中进行了初始化,并且在调用计时器上的 Dispose() 方法之前只运行了 3 次迭代。然而结果是相似的。
  • 只是添加对 API 的其他调用需要 180 到 500(最大)毫秒。所以这需要的时间非常长。我还注意到,在计时器的逻辑处理后,总是会调用 EventSource 错误方法。事件源的就绪状态尚未设置为关闭。
  • 您好 Fhevol,您的问题有什么更新吗?据我所知,您的控制器构造函数应标记为静态,否则 IIS 将根据请求创建新的控制器实例。

标签: c# javascript html angularjs server-sent-events


【解决方案1】:

我认为正确的格式是:

subscriber.Write("event: message\n");
subscriber.Write("data: {0}\n\n");

事件侦听器仅响应包含事件消息名称的事件(在本例中为 message)。这意味着服务器能够发送可以单独订阅的多种事件类型。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-06
    • 2019-06-14
    • 2013-04-09
    • 1970-01-01
    • 2018-12-30
    • 2013-08-29
    • 2012-10-23
    • 2016-04-12
    相关资源
    最近更新 更多