Heim  >  Artikel  >  Web-Frontend  >  HTML5 unterstützt vom Server gesendete Ereignisse

HTML5 unterstützt vom Server gesendete Ereignisse

大家讲道理
大家讲道理Original
2017-05-28 10:54:232369Durchsuche

Einfaches Sequenzdiagramm der traditionellen WEB-Anwendungskommunikation:

Heutzutage verfügen die meisten Web-Apps über Ajax, wie folgt:

HTML5 verfügt über eine SSE-Funktion (Server-Sent Events), die es dem Server ermöglicht, Daten an den Client zu übertragen. (normalerweise Daten-Push genannt). Basierend auf dem Daten-Push werden neue Daten in der Datenquelle sofort an den Client gesendet, ohne auf die Client-Anfrage warten zu müssen. Bei diesen neuen Daten kann es sich um aktuelle Nachrichten, aktuelle Börsenkurse, Chat-Nachrichten von Freunden, Wettervorhersagen usw. handeln.

Die Funktionen von Daten-Pull und -Push sind gleich und Benutzer erhalten neue Daten. Aber Data Push hat einige Vorteile. Sie haben vielleicht gehört, dass Comet, Ajax Push, Reverse Ajax, HTTP Streaming, WebSockets und SSE unterschiedliche Technologien sind. Der wohl größte Vorteil ist die geringe Latenz. SSE wird von Webanwendungen verwendet, um Daten zu aktualisieren, ohne dass eine Aktion des Benutzers erforderlich ist.
Möglicherweise haben Sie schon von HTML5-WebSockets gehört, die auch Daten an den Client übertragen können. WebSockets ist eine komplexere Technologie zur Implementierung des Servers, es handelt sich jedoch um einen echten Vollduplex-Socket. Der Server kann Daten an den Client senden, und der Client kann auch Daten an den Server zurücksenden. SSE arbeitet mit dem HTTP/HTTPS-Protokoll und unterstützt Proxyserver und Authentifizierungstechnologien. SSE ist ein Textprotokoll und Sie können es problemlos debuggen. Wenn Sie hauptsächlich Binärdaten vom Server zum Client senden müssen, ist WebSocket die bessere Wahl. Der Unterschied zwischen SSE und WebSocket wird weiter unten in diesem Artikel erläutert.

HTML5-Server-gesendetes -Ereignis (Server-gesendetes Ereignis) ermöglicht Webseiten, Aktualisierungen zu erhalten vom Server
Server-Sent-Ereignis – Einseitige Nachrichtenübermittlung
Das Server-Sent-Ereignis bezieht sich darauf, dass die Webseite automatisch Aktualisierungen vom Server erhält.
Dies war früher auch möglich, wenn die Webseite nachfragen musste, ob ein Update verfügbar ist. Durch das Senden von Ereignissen über den Server können Updates automatisch eintreffen.
Beispiele: Facebook-/Twitter-Updates, Bewertungsaktualisierungen, neue Blogbeiträge, Veranstaltungsergebnisse usw.

Browser-Unterstützung (Alle gängigen Browser unterstützen vom Server gesendete Ereignisse, außer Internet Explorer.)

EventSource-Push (Ajax-Normalabfrage):

Verarbeitungsprozess:

Der Client richtet das EventSourceObjekt ein und sendet kontinuierlich Anfragen an den Server über das http-Protokoll. Das Antwortdatenformat des Servers an den Client besteht aus vier Teilen: Ereignis, Daten, ID und Leerzeile. Nachdem der Client die Antwortdaten vom Server empfangen hat, findet er den Ereignis-Listener, der dem EventSource-Objekt entspricht, basierend auf dem Ereignisereigniswert.

Vom Server gesendete Ereignisbenachrichtigung empfangen
Das EventSource-Objekt wird zum Empfangen der vom Server gesendeten Ereignisbenachrichtigung verwendet:


    //创建一个新的 EventSource 对象,规定发送更新的页面的 URL
    var source = new EventSource("../api/MyAPI/ServerSentEvents");    //默认支持message事件
    source.onmessage = function (event) {
        console.log(source.readyState);
        console.log(event);
    };


Beispielanalyse:
Erstellen Sie ein neues EventSource-Objekt und geben Sie dann die URL der Seite an, an die Aktualisierungen gesendet werden sollen (in diesem Fall „demo_sse.php“) 🎜> Parameter URL ist Die Server-URL muss sich in derselben Domäne befinden wie die URL der aktuellen Webseite (domain), und das Protokoll und der Port müssen identisch sein . Jedes Mal, wenn ein Update empfangen wird, tritt das onmessage-Ereignis auf

Unterstützung für vom Server gesendete Ereignisse erkennen

Im folgenden Beispiel haben wir einen zusätzlichen Code zur Erkennung geschrieben Vom Server gesendete Ereignisse Browserunterstützung für:



if(!!EventSource && typeof(EventSource)!=="undefined")
{    // 浏览器支持 Server-Sent
    // 一些代码.....}else{    // 浏览器不支持 Server-Sent..}


Serverseitiges Codebeispiel

Damit das obige Beispiel funktioniert Um zu funktionieren, benötigen Sie außerdem einen Server, der Datenaktualisierungen senden kann (z. B. PHP,

ASP
, ASP.NET, Java). Die Syntax des serverseitigen Event-Streamings ist sehr einfach. Sie
müssen den Header „Content-Type“ auf „text/event-stream“ setzen. Jetzt können Sie mit dem Senden des Event-Streams beginnen. Ich kenne nur C#
, daher habe ich den ApiController in ASP.NETs MVC verwendet, um die einfachste Serverseite zu schreiben:


    public class MyAPIController : ApiController
    {        /// <summary>
        /// ...api/MyAPI/ServerSentEvents        /// </summary>
        /// <returns></returns>        [HttpGet, HttpPost]        public Task<HttpResponseMessage> ServerSentEvents()
        {            //Response.ContentType = "text/event-stream"            //Response.Expires = -1            //Response.Write("data: " & now())            //Response.Flush()
            
            string data = "id: 123456\nevent: message\ndata: 666\n\n";

            HttpResponseMessage response = new HttpResponseMessage
            {                //注意:ContentType = "text/event-stream"
                Content = new StringContent(data, Encoding.GetEncoding("UTF-8"), "text/event-stream")
            };            return Task.FromResult(response);
        }
    }

Code-Erklärung:
Setzen Sie den Header „Content-Type“ auf „text/event-stream“
Geben Sie an, dass die Seite nicht zwischengespeichert wird
Geben Sie das Sendedatum aus ( immer mit „Daten:“ Anfang)
Ausgabedaten auf der Webseite aktualisieren


EventSource-Objekt

Neu generiert Das EventSource-Instanzobjekt verfügt über ein readyState--Attribut , das den -Status der Verbindung angibt.

source.readyState
Es kann die folgenden Werte annehmen:

0, was a entspricht Konstante EventSource.CONNECTING, die angibt, dass die Verbindung nicht hergestellt wurde oder getrennt wurde.

 1, was der Konstante EventSource.OPEN entspricht und anzeigt, dass die Verbindung hergestellt wurde und Daten akzeptiert werden können.

 2, was der Konstante EventSource.CLOSED entspricht und anzeigt, dass die Verbindung getrennt wurde und nicht wieder hergestellt wird.


Im obigen Beispiel verwenden wir das onmessage-Ereignis, um die Nachricht abzurufen. Es können jedoch auch andere Ereignisse verwendet werden:
Ereignisbeschreibung
onopenBeim Öffnen der Verbindung zum Server
onmessage Wenn eine Nachricht empfangen wird
bei einem Fehler Wenn ein Fehler auftritt

Ereignis öffnen

Einmal Die Verbindung wird hergestellt, das Open-Ereignis wird ausgelöst und die entsprechende Callback-Funktion kann definiert werden.

source.onopen = function(event) {
// handle open event
};

// oder

source.addEventListener("open", function(event) {
// open event verarbeiten
}, false);
message event

Receive Das Nachrichtenereignis wird ausgelöst, wenn die Daten empfangen werden.

source.onmessage = function(event) {
var data = event.data;
var origin = event.origin;
var lastEventId = event.lastEventId;
// handle message
};

// oder

source.addEventListener("message", function(event) {
var data = event.data;
var origin = event.origin;
var lastEventId = event.lastEventId;
// Nachricht verarbeiten
}, false);
Der Parameter Objektereignis hat die folgenden Attribute:

Daten: serverseitig Die zurückgegebenen Daten (im Textformat).

Ursprung: Der Domänennamenteil der serverseitigen URL, also das Protokoll, der Domänenname und der Port.

lastEventId: Die Nummer der vom Server gesendeten Daten. Wenn keine Zahl vorhanden ist, ist dieses Attribut leer.

Fehlerereignis

Wenn ein Kommunikationsfehler auftritt (z. B. Verbindungsunterbrechung), wird das Fehlerereignis ausgelöst.

source.onerror = function(event) {
// Fehlerereignis behandeln
};

// oder

source.addEventListener("error" , function(event) {
// Fehlerereignis behandeln
}, false);
Benutzerdefiniertes Ereignis

Der Server kann mit dem Browser benutzerdefinierte Ereignisse vereinbaren. In diesem Fall lösen die zurückgesendeten Daten das Nachrichtenereignis nicht aus.

source.addEventListener("foo", function(event) {
var data = event.data;
var origin = event.origin;
var lastEventId = event.lastEventId;
// Nachricht verarbeiten
}, false);
Der obige Code zeigt an, dass der Browser das foo-Ereignis überwacht.

close-Methode

close-Methode wird zum Schließen der Verbindung verwendet.

Quelle.close();
Datenformat
Übersicht

HTTP-Header der vom Server gesendeten Daten Die Informationen lauten wie folgt:

Content-Type: text/event-stream
Cache- Steuerung: kein Cache
Verbindung: Keep-Alive
Die folgenden Zeilen haben das folgende Format:

Feld: valuen
Feld kann vier Werte annehmen: „Daten“, „Ereignis“, „ID“ oder „Wiederholung“, was bedeutet, dass es vier Arten von Header-Informationen gibt. Jede HTTP-Kommunikation kann eine oder mehrere dieser vier Arten von Header-Informationen enthalten. n steht für ein Zeilenumbruchzeichen.

Zeilen, die mit einem Doppelpunkt beginnen, stellen Kommentare dar. Normalerweise sendet der Server von Zeit zu Zeit einen Kommentar an den Browser, um die Verbindung aufrechtzuerhalten.

: Dies ist ein Kommentar
Hier einige Beispiele.

: Dies ist ein Teststreamnn

Daten: etwas Textnn

data: another message\n
data: with two lines \n\n
data:数据栏

数据内容用data表示,可以占用一行或多行。如果数据只有一行,则像下面这样,以“\n\n”结尾

data:  message\n\n
如果数据有多行,则最后一行用“\n\n”结尾,前面行都用“\n”结尾。

data: begin message\n
data: continue message\n\n
总之,最后一行的data,结尾要用两个换行符号,表示数据结束。

以发送JSON格式的数据为例。

data: {\n
data: "foo": "bar",\n
data: "baz", 555\n
data: }\n\n
id:数据标识符

数据标识符用id表示,相当于每一条数据的编号。

id: msg1\n
data: message\n\n
浏览器用lastEventId属性读取这个值。一旦连接断线,浏览器会发送一个HTTP头,里面包含一个特殊的“Last-Event-ID”头信息,将这个值发送回来,用来帮助服务器端重建连接。因此,这个头信息可以被视为一种同步机制。

event栏:自定义信息类型

event头信息表示自定义的数据类型,或者说数据的名字。

event: foo\n
data: a foo event\n\n

data: an unnamed event\n\n

event: bar\n
data: a bar event\n\n
上面的代码创造了三条信息。第一条是foo,触发浏览器端的foo事件;第二条未取名,表示默认类型,触发浏览器端的message事件;第三条是bar,触发浏览器端的bar事件。

retry:最大间隔时间

浏览器默认的是,如果服务器端三秒内没有发送任何信息,则开始重连。服务器端可以用retry头信息,指定通信的最大间隔时间。

retry: 10000\n

--------------------------------------------------------------------------------------

规范
Server-sent Events 规范是 HTML 5 规范的一个组成部分,具体的规范文档见参考资源。该规范比较简单,主要由两个部分组成:第一个部分是服务器端与浏览器端之间的通讯协议,第二部分则是在浏览器端可供 JavaScript 使用的 EventSource 对象。通讯协议是基于纯文本的简单协议服务器端的响应的内容类型是“text/event-stream”。响应文本的内容可以看成是一个事件流,由不同的事件所组成。每个事件由类型和数据两部分组成,同时每个事件可以有一个可选的标识符。不同事件的内容之间通过仅包含回车符和换行符的空行(“\r\n”)来分隔。每个事件的数据可能由多行组成。代码清单 1 给出了服务器端响应的示例:


retry: 10000\n
event: message\n
id: 636307190866448426\n
data: 2017/05/18 15:44:46\n\n


Chrome浏览器监视视图

响应报文头部:

响应报文内容:


每个事件之间通过空行来分隔。对于每一行来说,冒号(“:”)前面表示的是该行的类型,冒号后面则是对应的值。可能的类型包括:
类型为空白,表示该行是注释,会在处理时被忽略。
类型为 data,表示该行包含的是数据。以 data 开头的行可以出现多次。所有这些行都是该事件的数据。
类型为 event,表示该行用来声明事件的类型。浏览器在收到数据时,会产生对应类型的事件。
类型为 id,表示该行用来声明事件的标识符。
类型为 retry,表示该行用来声明浏览器在连接断开之后进行再次连接之前的等待时间。

当有多行数据时,实际的数据由每行数据以换行符连接而成。
如果服务器端返回的数据中包含了事件的标识符,浏览器会记录最近一次接收到的事件的标识符。如果与服务器端的连接中断,当浏览器端再次进行连接时,会通过 HTTP 头“Last-Event-ID”来声明最后一次接收到的事件的标识符。服务器端可以通过浏览器端发送的事件标识符来确定从哪个事件开始来继续连接。
对于服务器端返回的响应,浏览器端需要在 JavaScript 中使用 EventSource 对象来进行处理。EventSource 使用的是标准的事件监听器方式,只需要在对象上添加相应的事件处理方法即可。EventSource 提供了三个标准事件:

EventSource 对象提供的标准事件
名称   说明   事件处理方法
open   当成功与服务器建立连接时产生 onopen
message 当收到服务器发送的事件时产生 onmessage
error   当出现错误时产生 onerror

而且,服务器端可以返回自定义类型的事件。对于这些事件,可以使用 addEventListener 方法来添加相应的事件处理方法:


var es = new EventSource('events');
es.onmessage = function(e) {
    console.log(e.data);
};//自定义事件 myeventes.addEventListener('myevent', function(e) {
    console.log(e.data);
});


在指定 URL 创建出 EventSource 对象之后,可以通过 onmessage 和 addEventListener 方法来添加事件处理方法。当服务器端有新的事件产生,相应的事件处理方法会被调用。EventSource 对象的 onmessage 属性的作用类似于 addEventListener( ‘ message ’ ),不过 onmessage 属性只支持一个事件处理方法。

 

传统的网页都是浏览器向服务器“查询”数据,但是很多场合,最有效的方式是服务器向浏览器“发送”数据。比如,每当收到新的电子邮件,服务器就向浏览器发送一个“通知”,这要比浏览器按时向服务器查询(polling)更有效率。服务器发送事件(Server-Sent Events,简称SSE)就是为了解决这个问题,而提出的一种新API,部署在EventSource对象上。目前,除了IE,其他主流浏览器都支持。
简单说,所谓SSE,就是浏览器向服务器发送一个HTTP请求,然后服务器不断单向地向浏览器推送“信息”(message)。这种信息在格式上很简单,就是“信息”加上前缀“data: ”,然后以“\n\n”结尾。

SSE与WebSocket有相似功能,都是用来建立浏览器与服务器之间的通信渠道。两者的区别在于:

  WebSocket是全双工通道,可以双向通信,功能更强;SSE是单向通道,只能服务器向浏览器端发送。

  WebSocket是一个新的协议,需要服务器端支持;SSE则是部署在HTTP协议之上的,现有的服务器软件都支持。

  SSE是一个轻量级协议,相对简单;WebSocket是一种较重的协议,相对复杂。

  SSE默认支持断线重连,WebSocket则需要额外部署。

  SSE支持自定义发送的数据类型。

从上面的比较可以看出,两者各有特点,适合不同的场合。

 

个人完整的HTML5页面和C#(MVC实现服务端代码)如下:

前端HTML5页面:


<!DOCTYPE html><html><head>
    <meta charset="utf-8">
    <title>HTML5 服务器发送事件(Server-Sent Events)-单向消息传递</title>
    <meta name="author" content="熊仔其人" />
    <meta name="generator" content="2017-05-18" /></head><body>
    <h1>获取服务端更新数据</h1>
    <p id="result"></p><script>if(typeof(EventSource)!=="undefined")
{    //创建一个新的 EventSource 对象,规定发送更新的页面的 URL
    var source = new EventSource("../api/MyAPI/ServerSentEvents");    //默认支持open事件    source.onopen = function (event) {
        console.log(source.readyState);
        console.log(event);
    };    //默认支持error事件    source.onerror = function (event) {
        console.log(source.readyState);
        console.log(event);
    };    //默认支持message事件    source.onmessage = function (event) {
        console.log(source.readyState);
        console.log(event);
        document.getElementById("result").innerHTML += event.data + "<br>";
    };    //处理服务器响应报文中的自定义事件    source.addEventListener("CustomEvent", function (e) {
        console.log("唤醒自定义事件");
        console.log(e);
        document.getElementById("result").innerHTML += e.data + "<br>";
    });
}else{
    document.getElementById("result").innerHTML="抱歉,你的浏览器不支持 server-sent 事件...";
}</script></body></html>


C#写的服务器端:


using System;using System.Net.Http;using System.Text;using System.Threading.Tasks;using System.Web.Http;namespace WebTest.Controllers
{    /// <summary>
    /// api/{controller}/{id}    /// </summary>
    public class MyAPIController : ApiController
    {        static readonly Random random = new Random();        /// <summary>
        /// ...api/MyAPI/ServerSentEvents        /// </summary>
        /// <returns></returns>        [HttpGet, HttpPost]        public Task<HttpResponseMessage> ServerSentEvents()
        {            //Response.ContentType = "text/event-stream"            //Response.Expires = -1            //Response.Write("data: " & now())            //Response.Flush()
            
            string data = "";            if (random.Next(0, 10) % 3 == 0)
            {                //唤醒自定义的CustomEvent
                data = ServerSentEventData("这是自定义通知", DateTime.Now.Ticks.ToString(), "CustomEvent");
            }            else
            {                //唤醒默认的message
                data = ServerSentEventData(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss"), DateTime.Now.Ticks.ToString());
            }

            HttpResponseMessage response = new HttpResponseMessage
            {                //注意:ContentType = "text/event-stream"
                Content = new StringContent(data, Encoding.GetEncoding("UTF-8"), "text/event-stream")
            };            return Task.FromResult(response);
        }        public string ServerSentEventData(string data, string id, string _event = "message", long retry = 10000)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("retry:{0}\n", retry);
            sb.AppendFormat("event:{0}\n", _event);
            sb.AppendFormat("id:{0}\n", id);
            sb.AppendFormat("data:{0}\n\n", data);            return sb.ToString();
        }
        
    }
}


通信在页面上的显示结果:

通过Chrome监控网络交互时序:

通过Chrome浏览器控制台输出,下面是一轮ope、message、error事件的详情:

 

至此,大功告成。

 

Das obige ist der detaillierte Inhalt vonHTML5 unterstützt vom Server gesendete Ereignisse. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn