ホームページ  >  記事  >  ウェブフロントエンド  >  HTML5 はサーバー送信イベントをサポートします

HTML5 はサーバー送信イベントをサポートします

大家讲道理
大家讲道理オリジナル
2017-05-28 10:54:232424ブラウズ

従来の WEB アプリケーション通信の単純なシーケンス図:

現在、ほとんどの Web アプリは次のように Ajax を備えています:

HTML5 Server-Sent Events (SSE) 関数があります。サーバーがデータをクライアントにプッシュできるようにします。 (通常はデータプッシュと呼ばれます)。データ プッシュに基づいて、データ ソースに新しいデータがある場合、クライアントの要求を待たずに、そのデータがすぐにクライアントに送信されます。これらの新しいデータには、最新ニュース、最新の株価、友人からのチャット メッセージ、天気予報などが含まれます。

データのプルとプッシュの機能は同じで、ユーザーは新しいデータを取得します。ただし、データプッシュにはいくつかの利点があります。 Comet、Ajax プッシュ、リバース Ajax、HTTP ストリーミング、WebSocket、SSE は異なるテクノロジであることを聞いたことがあるかもしれません。おそらく最大の利点は低遅延です。 SSE は、ユーザーによるアクションを必要とせずにデータを更新するために Web アプリケーションによって使用されます。
HTML5 WebSocket について聞いたことがあるかもしれません。これはクライアントにデータをプッシュすることもできます。 WebSocket はサーバーを実装するためのより複雑なテクノロジですが、サーバーはデータをクライアントにプッシュでき、クライアントもデータをサーバーにプッシュできます。 SSE は HTTP/HTTPS プロトコルで動作し、プロキシ サーバーと認証テクノロジをサポートします。 SSE はテキスト プロトコルであり、簡単に デバッグ できます。主にバイナリ データをサーバーからクライアントに送信する必要がある場合は、WebSocket の方が適しています。 SSE と WebSocket の違いについては、この記事で後述します。

HTML5 サーバー送信イベント (サーバー送信イベント) を使用すると、Web ページがサーバーから 更新を取得できるようになります サーバー送信イベント -
一方向メッセージング サーバー送信イベントとは、サーバーから更新を自動的に取得する Web ページです。
これは、Web ページでアップデートが利用可能かどうかを尋ねる必要がある場合、以前も可能でした。サーバー経由でイベントを送信することで、更新を自動的に受信できます。
例: Facebook/Twitter の更新、評価の更新、新しいブログ投稿、イベントの結果など。

ブラウザのサポート (Internet Explorer を除くすべての主要なブラウザはサーバー送信イベントをサポートします。)

EventSource プッシュ (Ajax 通常のポーリング):

処理プロセス:

クライアントは EventSource

オブジェクトを確立し、継続的に作成しますhttp プロトコルを介してサーバーにリクエストを送信します。サーバーからクライアントへの応答データ形式は、event、data、id、空白行の 4 つの部分で構成されます。サーバーから応答データを受信した後、クライアントはイベント イベント値に基づいて EventSource オブジェクトに対応するイベント リスナーを見つけます。

サーバーから送信されたイベント通知を受信する

EventSource オブジェクトは、サーバーから送信されたイベント通知を受信するために使用されます:


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


分析例:

新しい EventSource オブジェクトを作成し、ページの URL を指定します更新を送信するには (この場合は「demo_sse.php」)、
パラメーターの url はサーバー URL であり、現在の Web ページの URL (domain) と同じドメイン内にある必要があります。プロトコルとポートは同じである必要があります 更新を受信するたびに onmessage イベントが発生します

サーバー送信イベントのサポートを検出する

次の例では、サーバー送信イベントのブラウザー サポートを検出する追加のコードを作成しました。


サーバー側のコード例

上記の例が機能するには、データ更新を送信できるサーバー (PHP、

ASP

ASP.NET

、Java など) も必要です。
サーバーサイドイベントストリーミングの構文は非常に簡単です。 「Content-Type」ヘッダーを「text/event-stream」に設定する必要があります。これで、イベント ストリームの送信を開始できるようになりました。 私は C#
しか知らないので、ASP.NET の MVC の ApiController を使用して、最も単純なサーバーサイドを作成しました:

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

コード説明:
ヘッダーの「Content-Type」を「text/event-stream」に設定します
ページをキャッシュしないように指定します 送信日を出力します(常に「data: "」で始まります)
出力データを更新しますWeb ページへ


EventSource オブジェクト

新しく生成された EventSource インスタンス オブジェクトには、接続の

状態 を示す readyState 属性 があります。

source.

readyState次の値を取ることができます:

0、これは定数EventSource.CONNECTINGと同等であり、接続が確立されていないか、接続が切断されていることを示します。

1、定数 EventSource.OPEN に相当し、接続が確立され、データを受け入れることができることを示します。

2、定数 EventSource.CLOSED に相当し、接続が切断され、再接続されないことを示します。

上記の例では、onmessage イベントを使用してメッセージを取得します。ただし、他のイベントも使用できます。
イベントの説明

onopen サーバーへの接続が開かれたとき
onmessage メッセージが受信されたとき
onerror エラーが発生したとき

open イベント

接続が確立されると、open イベントがトリガーされ、対応する

コールバック関数 を定義できます。

source.onopen = function(event) {

// han
dleオープンイベント};

// または

source.addEvent

Listener("open", function(event) { / / handle open イベント
}, false);
message イベント

は、データを受信するときに message イベントをトリガーします。

source.onmessage = function(event) {

var data =event.data;
varorigin =event.origin;
var lastEventId =event.lastEventId;
// メッセージを処理します
};

// または

source.addEventListener("message", function(event) {

var data =event.data;
varorigin =event.origin;
var lastEventId =event.lastEventId;
// メッセージを処理します
}, false);
parametersオブジェクト イベントには次の属性があります:

data: サーバーから返されたデータ (テキスト形式)。

origin: サーバー側 URL のドメイン名部分、つまりプロトコル、ドメイン名、ポート。

lastEventId: サーバーによって送信されたデータの数。数値がない場合、この属性は空です。

エラーイベント

通信エラー(接続の中断など)が発生すると、エラーイベントがトリガーされます。

source.onerror = function(event) {

// エラーイベント
を処理する};

// または

source.addEventListener("error", function(event) {

// エラーイベント
を処理する}, false );
カスタム イベント

サーバーはブラウザとカスタム イベントについて合意できます。この場合、返送されたデータはメッセージ イベントをトリガーしません。

source.addEventListener("foo", function(event) {

var data =event.data;
varorigin =event.origin;
var lastEventId =event.lastEventId;
// メッセージを処理します
}, false);
上記のコードは、ブラウザが foo イベントを監視していることを示しています。

closeメソッド

closeメソッドは接続を閉じるために使用されます。

source.

close();データ形式
概要

サーバーから送信されるデータの

HTTPヘッダー情報は以下の通りです:

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive 以下の行は次の形式になります:

field: valuen

field は 4 つの値を取ることができます: "data" 、「event」、「id」、「retry」の 4 種類のヘッダー情報があることを意味します。各 HTTP 通信には、これら 4 種類のヘッダー情報のうち 1 つ以上を含めることができます。 n は改行文字を表します。

コロンで始まる行は

コメントを表します。通常、サーバーは接続を維持するためにブラウザに時々コメントを送信します。

: これはコメントです

ここにいくつかの例があります。

: これはテストストリームですnn

データ: テキストnn

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事件的详情:

 

至此,大功告成。

 

以上がHTML5 はサーバー送信イベントをサポートしますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。