65.9K
CodeProject 正在变化。 阅读更多。
Home

3 天学习 HTML 5 - 第 3 天 - 第 1 部分

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.98/5 (17投票s)

2016 年 4 月 19 日

CPOL

8分钟阅读

viewsIcon

31078

downloadIcon

1242

在本文中,我们将详细介绍服务器发送事件(Server Sent Events)。

引言

终于到了最后一天,第三天。我相信过去的两天你们都过得很愉快。这是最后的阶段——第三天。第三天写得有些不同。在第三天,我们将详细介绍服务器发送事件。 HTML5

 

完整列表

为什么需要服务器发送事件?

服务器发送事件(SSE)是一种技术,通过该技术,浏览器可以通过 HTTP 连接从服务器接收自动更新。

让我们通过一个场景来简化这个定义。假设我们有一个 HTML 页面。需求很简单。该 HTML 页面将不断地从服务器获取更新的数据并在 UI 中显示。

旧方法

完成此需求的一种传统方法是“轮询”。在轮询中,我们会向服务器发送一个 Ajax 请求并获取响应。一旦收到响应,负责此通信的 HTTP 连接就会关闭。一段时间后,它将使用新的 HTTP 连接再次重复,并不断重复。这就是轮询的概念。

1 – 获取 HTML 页面

2 – 从 HTML 页面向服务器请求数据

流式响应的概念

持续的轮询会影响整体性能。一个解决方案是服务器进行流式响应。一旦发出请求,服务器将返回响应,但作为数据流。

流式传输

我敢肯定你见过 YouTube。它是流媒体的最佳范例。YouTube 不是一次性返回整个视频,而是只从服务器返回一小部分视频,YouTube 播放器就开始播放这一小部分视频。但服务器不会止步于此,它会定期不断地发送更多片段。这个概念被称为流媒体。更精确地说,对于视频,它被称为流媒体。

同样,其他数据也可以被流式传输。简单来说,客户端会向服务器请求一些数据,服务器返回一些数据,而不是结束执行和关闭连接,服务器会持续发送数据。一旦没有要发送的内容,服务器将完成执行并关闭连接。

注意:我们很快将使用 Asp.Net MVC 创建一个示例服务器端代码来演示数据流。

普通的 Ajax 调用无法实现流媒体

使用 XmlHttpRequest 进行的传统 Ajax 调用无法让我们获取数据流。使用 Ajax,我们将从 JavaScript 向服务器发送异步请求。一旦在 JavaScript 中收到响应,客户端就会自动关闭连接。它不会等待下一个流返回。

新方法 – 服务器发送事件

在 SSE 的情况下,情况会有点不同。这里我们将有两个东西:

  1. 服务器 – 它将不断发送数据流。
  2. 一个 HTML 页面,它将使用 EventSource 对象向服务器发出请求。EventSource 是一个用于处理 SSE 的新的 HTML5 概念。

EventSource 对象提供了一个回调函数,该函数将在服务器每次发送响应时执行。

1 – 获取 HTML 页面

2 – 从 HTML 页面向服务器请求数据

让我们通过演示来更好地理解它。

实验 21 – SSE 演示

步骤 1 - 创建服务器代码

在我们的示例中,我们将选择 Asp.Net MVC 作为服务器端技术。

注意:本文更侧重于 HTML 5 SSE,而不是 Asp.net MVC。如果您对 Asp.Net MVC 有先前的了解会更好,否则只需按照以下步骤准备服务器端部分。甚至不要犹豫从附带的示例中下载 MVC 项目并直接使用它。

步骤 1.1 – 创建 Asp.Net MVC 项目。

使用 Visual Studio 创建一个名为 ServerSentDemo 的新 Asp.Net MVC 项目。您可以从这里下载 Visual Studio。

在下一个对话框中,在模板部分选择“Empty”,在引用部分选择“MVC”,然后单击“OK”。

步骤 1.2- 创建控制器

右键单击 Controllers 文件夹,选择 AddNew>>Controller。

在下一个对话框中选择“MVC 5 Controller - Empty”,然后单击“OK”。

将名称设置为 SSEController,然后单击“OK”。

步骤 1.3- 创建 Action 方法

在 SSEController 中创建名为 Index 的 Action 方法,如下所示。

publicvoid Index()
{
int i = 0;
do
    {
        Response.Write("Current Date:"+DateTime.Now+"
");
        Response.Flush();
        System.Threading.Thread.Sleep(2000);
        i++;
    } while (i<5);
}

正如您所见,Action 方法的返回类型设置为 void,并且通过 Response.Write 和 Response.Flush 显式生成并返回响应。

步骤 1.4 - 执行和测试

按 F5 并执行应用程序。

注意:为了测试返回数据流的服务器代码,Chrome 是最佳选择。因此,请在 Chrome 中执行应用程序。

导航到 SSEController 的 Index Action 并检查输出。

正如您所见,服务器正在以流的方式发送响应。每次数据流之间有 2 秒的间隔。

步骤 2 – 创建客户端代码

在实际场景中,我们不会将上述 URL 直接暴露给最终用户。相反,我们将创建一个用户友好的 URL,并使用 JavaScript 通过 HTML 5 概念 SSE 向上述 URL 发送请求。

步骤 2.1 – 创建 HTML 客户端文件。

只需创建一个 HTML 页面并将其命名为“SSEClient.html”。

将以下 HTML 放入新创建的 html 文件中。

<!DOCTYPEhtml>
<html>
<head>
<metaname="viewport"content="width=device-width"/>
<title>Index</title>
</head>
<body>
<ulid="messages"></ul>
</body>
</html>

这是一个简单的 HTML 内容,带有一个 div 标签。我们将在该 div 中显示服务器发送的响应。

步骤 2.2 – 实现 EventSource

在 HTML 文件中,在 Head 部分创建一个 script 标签,并像这样处理窗口的 onload 函数:

<scripttype="text/javascript">
window.onload = function () {
var o = new EventSource("https://:13971/SSE/Index");
};
</script>

正如您所见,在 onload 函数中创建了 EventSource 对象。这一行将向之前编写的服务器代码发出请求。

步骤 2.3 – 处理响应数据

EventSource 对象公开一个名为“onmessage”的属性。此属性需要一个函数作为值,该函数将在服务器每次发送内容时执行。编写以下代码。

var o = new EventSource("https://:13971/SSE/Index");
o.onmessage = function (e) {
var x = e.data;
var MyDiv = document.getElementById("messages");
    MyDiv.innerHTML = MyDiv.innerHTML + "<li>" + x+ "</li>";
}

步骤 2.4 – 执行和测试

只需双击 SSEClient.html 文件并执行它。(确保服务器代码已启动并正在运行。)

奇怪的是,您在输出中看不到任何内容。

出现这种预期输出的原因是运行时错误。

只需在浏览器中打开开发者工具。在 Chrome 中按 F12。

默认情况下,浏览器不允许向与当前页面不在同一域的服务器发出请求。简单来说,我们的 HTML 文件和服务器代码不在同一域。一个域名是“localhost:13971”,而另一个是本地(C://MyRND.....)。为了实现这一点,我们必须在服务器上启用 CORS。

 

步骤 3 – 在服务器上启用 CORS

打开之前创建的服务器项目。打开 Web.Config 文件。在 configuration 部分创建一个名为 system.webServer 的子标签,如下所示:

......
<system.webServer>
<httpProtocol>
<customHeaders>
<addname="Access-Control-Allow-Origin"value="*"/>
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>

注意:如果 configuration 部分已经包含 system.webServer 标签,则不要再次创建它。只需将 httpProtocol 标签放在其中,如上所示。

步骤 4 – 重新执行客户端

现在再次运行 SSECllient.html 文件。这次最后一个错误将得到解决,但不要期望有输出,因为新的运行时错误正在等待。使用开发者工具找出错误原因。

为了处理 SSE,我们需要一个发送数据流且 Content-Type 为“text/event-stream”的服务器。默认情况下它是“text/html”。

步骤 5 – 更改服务器响应 Content Type

打开服务器代码并将 Index Action 方法更改如下:

publicvoid Index()
{
    Response.ContentType = "text/event-stream";
int i = 0;
do
    {
        Response.Write("data:" + DateTime.Now + "\n\n");
        Response.Flush();
        System.Threading.Thread.Sleep(2000);
        i++;
    } while (i<5);
}

正如您所见,不仅 Content-Type 设置为“text/event-stream”,而且输出格式也发生了变化。对于 SSE,响应格式必须是“data:ActualDataInStringType\n\n”。这是一个固定格式。“data”是一个关键字,实际响应文本后面必须跟两个“\n”。

步骤 6 – 重新执行客户端

再次运行 SSEClient.html 文件。

所以,终于我们得到了输出。

自动重新连接?

您可能会在上述输出中看到一种奇怪的行为。如果您长时间保持客户端打开,您会注意到输出在 5 次输出后不会结束。在 5 次输出后,服务器将结束响应,因此连接将关闭。3 秒后,将立即向服务器发送一个新请求,并通过流式传输 5 个更多输出。此过程将永远重复。

出现这种行为的原因是 Event Source 对象的自动重连能力。SSE 在 HTTP 协议之上工作。负责将客户端连接到服务器的 EventSource 对象确保连接始终可用。工作原理如下:

  • 它向服务器发出第一个请求。
  • 服务器开始处理请求并不断发送数据,而不结束响应。在客户端,每次收到响应时,EventSource 对象的 onmessage 回调都会被触发。
  • EventSource 对象会在每次连接关闭后 3 秒自动尝试重新连接到服务器。

此重试时间将由服务器决定。服务器可以在响应中返回重试时间。在这种情况下,响应字符串必须包含“retry”关键字。示例如下:

“retry:5000\ndata:SukeshMarla\n\n”

如果连接在收到上述数据后关闭,将在 5 秒后尝试重新连接。

关闭连接

这只能在客户端完成。在客户端,我们必须调用 EventSource 对象的 close 方法。示例:

var o = new EventSource("https://:13971/SSE/Index2");
.
.
.
o.close()

指定事件名称

单个服务器能够在不同情况下向客户端发送不同的事件。这可以通过在响应字符串中包含事件名称来完成。在这种情况下,在客户端,可以设置一个事件监听器来监听该特定事件。让我们举一个简单的例子。

步骤 1 创建一个新的 Action 方法 Index2,如下所示:

publicvoid Index2()
{
    Response.ContentType = "text/event-stream";
int i = 0;
do
    {
if (i == 0)
            Response.Write("event:first\ndata:" + DateTime.Now + "\n\n");
elseif (i == 4)
            Response.Write("event:last\ndata:" + DateTime.Now + "\n\n");
else
            Response.Write("data:" + DateTime.Now + "\n\n");
        Response.Flush();
        System.Threading.Thread.Sleep(2000);
        i++;
    } while (i < 5);
}

步骤 2 – 创建一个新的 HTML 文件,如下所示:

<!DOCTYPEhtml>
<html>
<head>
<metaname="viewport"content="width=device-width"/>
<title>Index</title>
<scripttype="text/javascript">
    window.onload = function () {
var o = new EventSource("https://:13971/SSE/Index2");
        o.onmessage = function (e) {
var x = e.data;
var MyDiv = document.getElementById("messages");
            MyDiv.innerHTML = MyDiv.innerHTML + "<li>" + x+"</li>";
        }
        o.addEventListener("first", function (e) {
            document.getElementById('FirstMessage').innerHTML = e.data;
        });
        o.addEventListener("last", function (e) {
            document.getElementById('LastMessage').innerHTML = e.data;
        });
    };
</script>
</head>
<body>
<h1id="FirstMessage"></h1>
<ulid="messages"></ul>
<h1id="LastMessage"></h1>
</body>
</html>

步骤 3 – 执行并测试应用程序

执行服务器,然后执行客户端。

就这样。

希望大家都能愉快地阅读这篇文章。请务必分享您对本文的评论和想法。通过twitterFacebook保持联系,以获取有关我帖子的定期更新。

© . All rights reserved.