서버 전송 이벤트는 HTML 5 사양의 구성 요소이며 실시간으로 서버에서 브라우저로 데이터를 푸시하는 데 사용할 수 있습니다. 유사한 COMET 및 WebSocket 기술과 비교할 때 서버 푸시 이벤트는 사용이 더 간단하고 서버 측에서 변경이 덜 필요합니다. 일부 유형의 애플리케이션의 경우 서버 푸시 이벤트가 가장 좋은 옵션입니다.
WebSocket
HTML 5 서버 푸시 이벤트를 소개하기 전에 먼저 위에서 언급한 서버 측 데이터 푸시 기술 중 일부를 소개합니다. 첫 번째는 웹소켓입니다. WebSocket 사양은 HTML 5의 중요한 부분이며 많은 주류 브라우저에서 지원되었습니다. WebSocket을 기반으로 개발된 애플리케이션도 많이 있습니다. 이름에서 알 수 있듯이 WebSocket은 TCP 프로토콜을 기반으로 하는 소켓 연결을 사용합니다. WebSocket을 사용하면 실제로 서버와 브라우저 사이에 소켓 연결이 설정되어 양방향 데이터 전송이 가능해집니다. WebSocket은 매우 강력하고 유연하게 사용할 수 있으며 다양한 시나리오에 적용할 수 있습니다. 그러나 WebSocket 기술은 일반 웹 애플리케이션과 다른 서버 측 및 브라우저 측 구현을 포함하여 상대적으로 복잡합니다.
Polling
WebSocket 외에도 다른 구현 방법은 HTTP 프로토콜을 기반으로 실시간 푸시 효과를 구현합니다. 첫 번째 방법은 간단한 폴링(Polling)입니다. 즉, 브라우저가 주기적으로 서버에 요청을 보내 데이터 업데이트가 있는지 확인합니다. 이 접근 방식은 비교적 간단하며 어느 정도 문제를 해결할 수 있습니다. 그러나 폴링 간격은 신중하게 고려해야 합니다. 폴링 간격이 너무 길면 사용자는 업데이트된 데이터를 제때에 받을 수 없으며, 폴링 간격이 너무 짧으면 쿼리 요청이 너무 많아 서버에 부담이 커집니다.
단점:
1: 폴링은 클라이언트에 의해 시작되므로 특정 정보가 만료되었는지 여부를 판단하기 어렵기 때문에 서버는 내가 푸시하려는 콘텐츠가 만료되었는지 여부를 확인할 수 없습니다. 모든 클라이언트에 푸시된 경우 서버는 많은 양의 데이터를 캐시해야 합니다. 데이터가 데이터베이스에 저장되어 있으면 모든 요청에 대해 데이터베이스를 쿼리해야 하는데, 이는 데이터베이스와 시스템 설계 모두에 있어 큰 과제입니다.
2: 요청 빈도가 너무 높습니다. 각 요청 패킷에는 동일한 데이터가 포함되어 있습니다. 이는 PC에는 큰 문제가 아닐 수 있지만 모바일 클라이언트에는 아마도 최고가 아닐 것입니다. 해결책. 특히 권한 판단과 관련하여 서버의 논리와 효율성도 사용자 경험을 감소시킵니다.
COMET
COMET 기술은 단순 폴링의 단점을 개선하고 롱 폴링을 사용합니다. 긴 폴링 방법에서는 서버가 응답이 완료된 후 즉시 연결을 닫는 대신 각 요청 동안 일정 시간 동안 연결을 열어 둡니다. 이것의 장점은 연결이 열려 있는 동안 서버에서 생성된 데이터 업데이트가 적시에 브라우저에 반환될 수 있다는 것입니다. 이전의 긴 연결이 닫히면 브라우저는 즉시 새로운 긴 연결을 열어 요청을 계속합니다. 그러나 COMET 기술을 구현하려면 서버 측과 브라우저 측 모두에서 타사 라이브러리의 지원이 필요합니다.
요즘 대부분의 웹 앱에는 다음과 같은 Ajax가 있습니다.
위에서 언급한 4가지 기술을 종합적으로 비교하면 간단합니다. 폴링은 고유한 결함으로 인해 권장되지 않습니다. COMET 기술은 HTML 5 표준의 일부가 아니며 표준 준수 관점에서 사용이 권장되지 않습니다. WebSocket 사양과 서버 푸시 기술은 모두 HTML 5 표준의 구성 요소이며 주류 브라우저에서 기본 지원을 제공하므로 권장됩니다. 그러나 WebSocket 사양은 더 복잡하며 복잡한 양방향 데이터 통신이 필요한 시나리오에 적합합니다. 간단한 서버 데이터 푸시 시나리오의 경우 서버 푸시 이벤트를 사용하는 것으로 충분합니다.
데이터 기반 푸시는 데이터 소스에 새로운 데이터가 있으면 클라이언트 요청을 기다리지 않고 즉시 클라이언트로 전송됩니다. 이 새로운 데이터에는 최신 뉴스, 최신 주식 시세, 친구의 채팅 메시지, 일기 예보 등이 포함될 수 있습니다.
데이터 가져오기 및 푸시 기능은 동일하며 사용자는 새로운 데이터를 얻습니다. 그러나 데이터 푸시에는 몇 가지 장점이 있습니다. Comet, Ajax 푸시, 역방향 Ajax, HTTP 스트리밍, WebSocket 및 SSE는 서로 다른 기술이라는 말을 들어보셨을 것입니다. 아마도 가장 큰 장점은 낮은 지연 시간일 것입니다. SSE는 웹 애플리케이션에서 사용자의 조치 없이 데이터를 새로 고치는 데 사용됩니다.
WebSocket은 서버를 구현하는 데 있어 더 복잡한 기술이지만 진정한 전이중 소켓입니다. 서버는 데이터를 클라이언트에 푸시할 수 있고 클라이언트는 데이터를 다시 서버에 푸시할 수도 있습니다. SSE는 HTTP/HTTPS 프로토콜과 함께 작동하며 프록시 서버 및 인증 기술을 지원합니다. SSE는 텍스트 프로토콜이며 쉽게 디버깅할 수 있습니다. 대부분의 바이너리 데이터를 서버에서 클라이언트로 보내야 한다면 WebSocket이 더 나은 선택입니다.
다행히 Html5는 다음과 같은 방법을 제공합니다. 서버 전송 이벤트에는 새로운 HTML 요소 EventSource와 새로운 MIME 유형 text/event-stream이 포함되어 있어 요구 사항을 충족합니다.
서버에서 보낸 이벤트 API는 EventSource 인터페이스입니다. 새 EventSource 객체를 생성할 때 이벤트를 허용하는 URI를 지정할 수 있습니다. 예:
var evtSource = new EventSource("ssedemo.php");
<!DOCTYPE html><html><head> <title>sever Sent Event实例1</title></head><body> <h2>sever Sent Event实例1</h2> <p id="result"></p> <script type="text/javascript"> var result = document.getElementById('result'); if (typeof (EventSource) !== 'undefined') { //创建事件源 var source = new EventSource('test.php'); //监听事件源发送过来的数据 source.onmessage = function(event){ result.innerHTML +=event.data +'<br>'; } }else{ result.innerHTML += "您的浏览器不支持server sent Event"; } </script></body></html>
<?php //指定发送事件流的MIME为text/event-stream header('Content-Type:text/event-stream'); //不缓存服务端发送的数据 header('Cache-Control:no-cache'); //指定服务器发送的事件名 echo "event:test\n\n"; // 定义服务器向客户端发送的数据 echo "data:服务器当前时间为:".date('Y-m-d H:i:s')."\n\n"; //向客户端发送数据流 flush(); ?>
헤더 "Content-Type"을 "text/event-stream"으로 설정
페이지가 캐시되지 않도록 지정
전송된 내용을 출력 날짜(항상 "data: "로 시작)
웹페이지에 출력 데이터 새로고침
아마도 모든 사람이 정보가 푸시된 것을 알아차렸을 것입니다. php에서는 "nn"이 종료 플래그로 사용됩니다. 테스트 후 "nn"이 종료 플래그로 사용되지 않으면 클라이언트는 푸시된 값을 받을 수 없습니다. 또한 만들어야 하는 특별한 설명이 있습니다. 푸시된 정보 형식은 "data:contentnn"이어야 하며, 그렇지 않은 경우입니다. . .
이벤트 스트림은 단순한 텍스트 데이터 스트림입니다. 텍스트는 UTF-8 형식으로 인코딩되어야 합니다. 줄은 구분 기호 역할을 합니다. 콜론으로 시작하는 줄 주석 줄은 무시됩니다.
각 메시지는 여러 필드로 구성되며 각 필드는 필드 이름, 콜론 및 필드 값으로 구성됩니다.
필드
이벤트
이벤트 유형입니다. 이 필드를 지정하면 클라이언트에서 메시지를 수신합니다. 이벤트가 수신되면 현재 EventSource 객체에서 이벤트가 트리거됩니다. 이벤트 유형은 메시지가 있는 경우 addEventListener() 메서드를 사용하여 명명된 이벤트 유형을 수신할 수 있습니다. 이벤트 필드가 없으면 onmessage 속성에 대한 이벤트 처리 기능이 트리거됩니다.
data
메시지의 데이터 필드입니다. 메시지에 여러 데이터 필드가 포함된 경우 클라이언트는 줄바꿈을 사용하여 이를 필드 값으로 문자열로 연결합니다. 현재 EventSource 객체의 내부 부분 "Last Event ID" 속성의 속성 값.
retry
재연결 시간을 지정하는 정수 값( 밀리초 단위), 필드 값이 정수가 아닌 경우 무시됩니다.
참고: 텍스트 줄에 콜론이 포함되어 있지 않으면 전체 텍스트 줄이 필드 이름으로 구문 분석되고 해당 필드 값은 비어 있게 됩니다.
EventSource 객체 표준 이벤트 제공
<!DOCTYPE html><html><head> <title>sever Sent Event实例1</title></head><body> <h2>sever Sent Event实例1</h2> <button onclick="closeCnt()">断开连接</button> <p id="result"></p> <script type="text/javascript"> var result = document.getElementById('result'); if (typeof (EventSource) !== 'undefined') { //创建事件源 var source = new EventSource('test.php'); //监听事件源发送过来的数据 source.onmessage = function(event){ result.innerHTML +=event.data +'<br>'; } source.onopen = connectionOpen; source.onclose = connectionClose; function connectionOpen(){ if (source.readyState == 0) { result.innerHTML +='未建立连接<br>'; } if (source.readyState == 1) { result.innerHTML +='连接成功<br>'; } } function connectionClose(){ result.innerHTML += "关闭连接,readyState属性值为:" + source.readyState + '<br>'; } function closeCnt(){ source.close(); result.innerHTML += "断开连接,readyState属性值为:" + source.readyState + '<br>'; } }else{ result.innerHTML += "您的浏览器不支持server sent Event"; } </script></body></html>
在指定 URL 创建出 EventSource 对象之后,可以通过 onmessage 和 addEventListener 方法来添加事件处理方法。当服务器端有新的事件产生,相应的事件处理方法会被调用。EventSource 对象的 onmessage 属性的作用类似于 addEventListener( ‘ message ’ ),不过 onmessage 属性只支持一个事件处理方法。
<!DOCTYPE html><html><head> <title>sever Sent Event实例1</title></head><body> <h2>sever Sent Event实例1</h2> <p id="result"></p> <script type="text/javascript"> var result = document.getElementById('result'); if (typeof (EventSource) !== 'undefined') { //创建事件源 var source = new EventSource('test.php'); //自定义事件源发送过来的数据,事件名和php中事件名对应 source.addEventListener('myevent', 'updateRequests', false); // source.onmessage = function() { // result.innerHTML = event.data + '<br>'; // } function updateRequests(event){ result.innerHTML = event.data + '<br>'; } }else{ result.innerHTML += "您的浏览器不支持server sent Event"; } </script></body></html>
<?php //指定发送事件流的MIME为text/event-stream header('Content-Type:text/event-stream'); //不缓存服务端发送的数据 header('Cache-Control:no-cache'); //指定服务器发送的事件名 echo "event:myevent\n\n"; // 定义服务器向客户端发送的数据 echo "data:服务器当前时间为:".date('Y-m-d H:i:s')."\n\n"; //向客户端发送数据流 flush(); ?>
前端是HTML5,后端可以是PHP, JSP, Node.js, Asp.net等应用。
服务器推送事件(Server-sent Events)是 HTML 5 规范中的一个组成部分,可以用来从服务端实时推送数据到浏览器端。相对于与之类似的 COMET 和 WebSocket 技术来说,服务器推送事件的使用更简单,对服务器端的改动也比较小。对于某些类型的应用来说,服务器推送事件是最佳的选择。
WebSocket
在介绍 HTML 5 服务器推送事件之前,首先介绍一些上面提到的几种服务器端数据推送技术。第一种是 WebSocket。WebSocket 规范是 HTML 5 中的一个重要组成部分,已经被很多主流浏览器所支持,也有不少基于 WebSocket 开发的应用。正如名称所表示的一样,WebSocket 使用的是套接字连接,基于 TCP 协议。使用 WebSocket 之后,实际上在服务器端和浏览器之间建立一个套接字连接,可以进行双向的数据传输。WebSocket 的功能是很强大的,使用起来也灵活,可以适用于不同的场景。不过 WebSocket 技术也比较复杂,包括服务器端和浏览器端的实现都不同于一般的 Web 应用。
轮询
除了 WebSocket 之外,其他的实现方式是基于 HTTP 协议来达到实时推送的效果。第一种做法是简易轮询,即浏览器端定时向服务器端发出请求,来查询是否有数据更新。这种做法比较简单,可以在一定程度上解决问题。不过对于轮询的时间间隔需要进行仔细考虑。轮询的间隔过长,会导致用户不能及时接收到更新的数据;轮询的间隔过短,会导致查询请求过多,增加服务器端的负担。
缺点:
1:轮询是由客户端发起的,那么在服务端就不能判别我要推送的内容是否已经过期,因为我很难判断某个信息是否已经推送给全部的客户端,那么服务端就需要缓存大量的数据。如果数据保存在数据库,那么还要每次请求都需要查询数据库,这对数据库和系统设计都是一个很大的挑战。
2:请求的频率太高,每次的请求包中含有同样的数据,这对pc来说也许算不得什么,但是对于移动客户端来讲,这应该不是最佳的方案。尤其是遇到还要做权限判断的时候,那么服务端的逻辑和效率也会造成用户体验的降低。
COMET
COMET 技术改进了简易轮询的缺点,使用的是长轮询。长轮询的方式在每次请求时,服务器端会保持该连接在一段时间内处于打开状态,而不是在响应完成之后就立即关闭。这样做的好处是在连接处于打开状态的时间段内,服务器端产生的数据更新可以被及时地返回给浏览器。当上一个长连接关闭之后,浏览器会立即打开一个新的长连接来继续请求。不过 COMET 技术的实现在服务器端和浏览器端都需要第三方库的支持。
现在Web App中,大都有Ajax,是这样子:
综合比较上面提到的 4 种不同的技术,简易轮询由于其本身的缺陷,并不推荐使用。COMET 技术并不是 HTML 5 标准的一部分,从兼容标准的角度出发,也不推荐使用。WebSocket 规范和服务器推送技术都是 HTML 5 标准的组成部分,在主流浏览器上都提供了原生的支持,是推荐使用的。不过 WebSocket 规范更加复杂一些,适用于需要进行复杂双向数据通讯的场景。对于简单的服务器数据推送的场景,使用服务器推送事件就足够了。
基于数据推送是这样的,当数据源有新数据,它马上发送到客户端,不需要等待客户端请求。这些新数据可能是最新闻,最新股票行情,来自朋友的聊天信息,天气预报等。
数据拉与推的功能是一样的,用户拿到新数据。但数据推送有一些优势。 你可能听说过Comet, Ajax推送, 反向Ajax, HTTP流,WebSockets与SSE是不同的技术。可能最大的优势是低延迟。SSE用于web应用程序刷新数据,不需要用户做任何动作。
WebSocket은 서버를 구현하는 데 있어 더 복잡한 기술이지만 진정한 전이중 소켓입니다. 서버는 데이터를 클라이언트에 푸시할 수 있고 클라이언트는 데이터를 다시 서버에 푸시할 수도 있습니다. SSE는 HTTP/HTTPS 프로토콜과 함께 작동하며 프록시 서버 및 인증 기술을 지원합니다. SSE는 텍스트 프로토콜이며 쉽게 디버깅할 수 있습니다. 대부분의 바이너리 데이터를 서버에서 클라이언트로 보내야 한다면 WebSocket이 더 나은 선택입니다.
다행히 Html5는 다음과 같은 방법을 제공합니다. 서버 전송 이벤트에는 새로운 HTML 요소 EventSource와 새로운 MIME 유형 text/event-stream이 포함되어 있어 요구 사항을 충족합니다.
서버에서 보낸 이벤트 API는 EventSource 인터페이스입니다. 새 EventSource 객체를 생성할 때 이벤트를 허용하는 URI를 지정할 수 있습니다. 예:
var evtSource = new EventSource("ssedemo.php");
<!DOCTYPE html><html><head> <title>sever Sent Event实例1</title></head><body> <h2>sever Sent Event实例1</h2> <p id="result"></p> <script type="text/javascript"> var result = document.getElementById('result'); if (typeof (EventSource) !== 'undefined') { //创建事件源 var source = new EventSource('test.php'); //监听事件源发送过来的数据 source.onmessage = function(event){ result.innerHTML +=event.data +'<br>'; } }else{ result.innerHTML += "您的浏览器不支持server sent Event"; } </script></body></html>
<?php //指定发送事件流的MIME为text/event-stream header('Content-Type:text/event-stream'); //不缓存服务端发送的数据 header('Cache-Control:no-cache'); //指定服务器发送的事件名 echo "event:test\n\n"; // 定义服务器向客户端发送的数据 echo "data:服务器当前时间为:".date('Y-m-d H:i:s')."\n\n"; //向客户端发送数据流 flush(); ?>
헤더 "Content-Type"을 "text/event-stream"으로 설정
페이지가 캐시되지 않도록 지정
전송된 내용을 출력 날짜(항상 "data: "로 시작)
웹페이지에 출력 데이터 새로고침
아마도 모든 사람이 정보가 푸시된 것을 알아차렸을 것입니다. php에서는 "nn"이 종료 플래그로 사용됩니다. 테스트 후 "nn"이 종료 플래그로 사용되지 않으면 클라이언트는 푸시된 값을 받을 수 없습니다. 또한 만들어야 하는 특별한 설명이 있습니다. 푸시된 정보 형식은 "data:contentnn"이어야 하며, 그렇지 않은 경우입니다. . .
이벤트 스트림은 단순한 텍스트 데이터 스트림입니다. 텍스트는 UTF-8 형식으로 인코딩되어야 합니다. 줄은 구분 기호 역할을 합니다. 콜론으로 시작하는 줄 주석 줄은 무시됩니다.
각 메시지는 여러 필드로 구성되며 각 필드는 필드 이름, 콜론 및 필드 값으로 구성됩니다.
필드
이벤트
이벤트 유형입니다. 이 필드를 지정하면 클라이언트에서 메시지를 수신합니다. 이벤트가 수신되면 현재 EventSource 객체에서 이벤트가 트리거됩니다. 이벤트 유형은 메시지가 있는 경우 addEventListener() 메서드를 사용하여 명명된 이벤트 유형을 수신할 수 있습니다. 이벤트 필드가 없으면 onmessage 속성에 대한 이벤트 처리 기능이 트리거됩니다.
data
메시지의 데이터 필드입니다. 메시지에 여러 데이터 필드가 포함된 경우 클라이언트는 줄바꿈을 사용하여 이를 필드 값으로 문자열로 연결합니다. 현재 EventSource 객체의 내부 부분 "Last Event ID" 속성의 속성 값.
retry
재연결 시간을 지정하는 정수 값( 밀리초 단위), 필드 값이 정수가 아닌 경우 무시됩니다.
참고: 텍스트 줄에 콜론이 포함되어 있지 않으면 전체 텍스트 줄이 필드 이름으로 구문 분석되고 해당 필드 값은 비어 있게 됩니다.
EventSource 객체 표준 이벤트 제공
<!DOCTYPE html><html><head> <title>sever Sent Event实例1</title></head><body> <h2>sever Sent Event实例1</h2> <button onclick="closeCnt()">断开连接</button> <p id="result"></p> <script type="text/javascript"> var result = document.getElementById('result'); if (typeof (EventSource) !== 'undefined') { //创建事件源 var source = new EventSource('test.php'); //监听事件源发送过来的数据 source.onmessage = function(event){ result.innerHTML +=event.data +'<br>'; } source.onopen = connectionOpen; source.onclose = connectionClose; function connectionOpen(){ if (source.readyState == 0) { result.innerHTML +='未建立连接<br>'; } if (source.readyState == 1) { result.innerHTML +='连接成功<br>'; } } function connectionClose(){ result.innerHTML += "关闭连接,readyState属性值为:" + source.readyState + '<br>'; } function closeCnt(){ source.close(); result.innerHTML += "断开连接,readyState属性值为:" + source.readyState + '<br>'; } }else{ result.innerHTML += "您的浏览器不支持server sent Event"; } </script></body></html>
在指定 URL 创建出 EventSource 对象之后,可以通过 onmessage 和 addEventListener 方法来添加事件处理方法。当服务器端有新的事件产生,相应的事件处理方法会被调用。EventSource 对象的 onmessage 属性的作用类似于 addEventListener( ‘ message ’ ),不过 onmessage 属性只支持一个事件处理方法。
<!DOCTYPE html><html><head> <title>sever Sent Event实例1</title></head><body> <h2>sever Sent Event实例1</h2> <p id="result"></p> <script type="text/javascript"> var result = document.getElementById('result'); if (typeof (EventSource) !== 'undefined') { //创建事件源 var source = new EventSource('test.php'); //自定义事件源发送过来的数据,事件名和php中事件名对应 source.addEventListener('myevent', 'updateRequests', false); // source.onmessage = function() { // result.innerHTML = event.data + '<br>'; // } function updateRequests(event){ result.innerHTML = event.data + '<br>'; } }else{ result.innerHTML += "您的浏览器不支持server sent Event"; } </script></body></html>
<?php //指定发送事件流的MIME为text/event-stream header('Content-Type:text/event-stream'); //不缓存服务端发送的数据 header('Cache-Control:no-cache'); //指定服务器发送的事件名 echo "event:myevent\n\n"; // 定义服务器向客户端发送的数据 echo "data:服务器当前时间为:".date('Y-m-d H:i:s')."\n\n"; //向客户端发送数据流 flush(); ?>
前端是HTML5,后端可以是PHP, JSP, Node.js, Asp.net等应用。
以上就是Html5 服务端推送 Server-Sent Event的内容,更多相关内容请关注PHP中文网(www.php.cn)!