آشنایی با SSE - وبسوکت از طریق HTML5

رویدادهای ارسال شده از سرور یا همون Server Sent Event یکی از APIهای بسیار کاربردی HTML5 برای توسعه دهنده های وب و یک امکان خیلی عالی با راه اندازی و اجرای ساده برای اپلیکیشنهای تحت وب و یا کارهاییست که نیاز مداوم به برقراری ارتباط با سرور برای کارهای مختلف نظیر بروزرسانی اطلاعات و یا بررسی داده ها دارند.

توی این مطلب به دلیل ساده نبودن آموزشهای فارسی در این زمینه، سعی میکنم خیلی ساده و راحت این تکنولوژی رو آموزش بدم.

- فرقش با وبسوکت چیه؟

وبسوکت (WebSocket) یه ارتباط دوطرفه کلاینت سرور هستش، ولی SSE تقریبا یکطرفست و شما کنترل زیادی در نحوه برقراری ارتباط با سرور ندارید. خود SSE با سرور سینک میشه و اگه اتفاقی (Event) که مشخص شده افتاد بهتون خبر میده.

- فرقش با ایجکس (Ajax) چیه؟

برخلاف ajax که نیاز هست مرتب و توی بازه های زمانی مشخص سمت سرور رو چک کرد، SSE بصورت اتوماتیک و از طریق کانکشنهای HTTP مرورگر رو بروزرسانی میکنه. یعنی عملا اتفاقی نمیفته مگر اینکه سرور به مرورگر کانکشنی بزنه و این رو اطلاع بده. این باعث میشه به مراتب سرعت کار بالاتر بره و منابع کمتری مصرف بشه.

https://stackoverflow.com/questions/8685750/difference-between-ajax-request-and-a-regular-browser-request

- مزیتش چیه؟

اجرا و پیاده سازیش در حد نوشتن چند خط ساده جاوااسکریپته.

نیاز به هیچ فایل و یا پلاگین اضافه ای نداره.

یادگیریش خیلی خیلی راحته و نیاز به خوندن صدها خط داکیومنت نداره.

چون native ساپورت میشه بصورت کاملا بهینه نوشته شده و با سرور ارتباط برقرار میشه.

جایگزین عالی برای Ajax نوشتن در جی کوئری و یا خود جاوااسکریپت (البته ساز و کار همونه ولی بهتر و سریعتر).

- برای چه کارهایی میشه ازش استفاده کرد؟

بروز کردن تقریبا ریل تایم (Real Time) اطلاعاتی مثل قیمت انواع ارز و ...

بروزکردن تیترهای خبری

نوشتن چت آنلاین (قسمت پشتیبانی سایتها) که نیاز به ارسال و دریافت خیلی سریع نیست.

دریافت تعداد یوزرهای آنلاین و یا آپدیت تعداد بازدید مطالب.

نمایش کامنتهای جدید و بسیاری دیگه از این کارها.

شروع آموزش

قدم اول رو از ساخت فایل سمت سرور شروع میکنم که اینجا من با زبان php این کار رو انجام میدم. اسم فایل رو server_time.php میذاریم؛ روند خیلی ساده هستش. کدها رو ببینیم و بعد توضیحات:

<?php
header("Content-Type: text/event-stream");
header("Cache-Control: no-cache");
// Get the current time on server
$currentTime = date("h:i:s", time());
// Send it in a message
echo "data: " . $currentTime . "nn";
flush();
?>

خط اول، نوع MIME را بصورت text/event-stream تنظیم می کنه، که برای استاندارد رویداد سمت سرور ضروریه. خط دوم به وب سرور میگه ذخیره سازی در حافظه ی نهان را غیرفعال کنه، در غیر این صورت، ممکنه خروجیِ اسکریپت در حافظه ی نهان ذخیره بشه و نتیجه ای که به کاربر نشون میدیم تکراری بشه چون کش شده. خطط سوم هم که ساعت جاری رو به این صورت چاپ میکنه. data: 12:18:25

هر پیامی که از طریق رویدادهای فرستاده شده از سمت سرور فرستاده میشه باید با “data:” شروع بشه و با متن اصلیِ پیام و کاراکتر خط جدید ("nn")دنبال بشه. (طبق این استاندارد)

در آخر از تابع flush() استفاده میکنیم تا اطمینان حاصل کنیم که داده ها به روشی صحیح ارسال شده باشن، بجای این که بافر بشن تا زمانی که کدِ PHP کامل بشه.

کل خطوط کد بالا در هر بار اجرا زمان سرور رو به صورت مثال: 8:17:38 برمیگردونه.

نمایش خروجی و ارتباط با سرور از طریق SSE

حالا که کدهای سمت سرور نوشته شد نوبت نوشتن کدهای سمت کلاینته که عموما با جاوااسکریپته. کد کامل صفحه به صورت زیر هستش:

<!DOCTYPE html>
<html lang="en">
<head>
<title>HTML5 Server-Sent Events</title>
<script type="text/javascript">
window.onload = function(){
var source = new EventSource("server_time.php");
source.onmessage = function(event){
document.getElementById("result").innerHTML += "New time received from web server: " + event.data + "<br>";
};
};
</script>
</head>
<body>
<div id="result">
<!--Server response will be inserted here-->
</div>
</body>
</html>


خط اول جاوااسکریپت به داکیومنت میگیم که منتظر بمونه صفحه کامل لود بشه و بعد بقیه کدها رو اجرا کنه.

خط دوم یک شی از EventSource برای کار با sse تعریف میشه و مسیر فایل پی اچ پی و یا asp هم به عنوان پارامتر بهش معرفی میکنیم.

خط سوم در رویداد onmessage و خطهای بعدش مشخص میکنیم که به محض دریافت پاسخ از سرور، با فرمتی که قبلا گفته شد اون رو دریافت و با استفاده از دستور getElement.innerHtml محتوا رو توی div با آیدی result جایگذاری کنه!

به همین سادگی کار تموم میشه :)) و هر چند میلی ثانیه این کار بصورت اتوماتیک برخلاف رکوئستهای ایجکسی که نیاز بود توی حلقه interVal گذاشته بشه تکرار و ساعتی که به کاربر نشون میدیم بروز رسانی میشه.

توضیحات تکمیلی:

کدهای چک کردن پشتیبانی مرورگر از SSE. نیاز به توضیح نیست و کاملا واضحه که قبل از استفاده باید این رو توی داکیومنت بنویسید.

 if ( typeof ( EventSource ) !== " undefined " ) {
                          // SSE پشتیانی مرورگر از
                          // کدهای مورد نظر
                      }
                 else  {
                          // SSE  عدم پشتیبانی مرورگر                 از                 
                          // کدهای مورد نظر
                     } 
مثل همیشه اینترنت کسپلورر از قافله تکنولوژی عقبه و فکر استفاده از SSE روی IE رو از سرتون بیرون کنید!

از این مطالب برای نوشتن اصولی تر این آموزش کمک گرفته شده:

https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events

https://softskill.ir/learn/web-development/html-tutorial/html5-server-sent-events

https://github.com/mdn/dom-examples/tree/master/server-sent-events

http://developer1.ir/HTML_5/SSE.aspx

https://www.w3schools.com/html/html5_serversentevents.asp

https://hpbn.co/server-sent-events-sse/#event-stream-protocol

https://web.tosinso.com/articles/34351/html-5-api-sse-%D8%B1%D9%88%DB%8C%D8%AF%D8%A7%D8%AF-%D9%87%D8%A7%DB%8C-%D8%A7%D8%B1%D8%B3%D8%A7%D9%84%DB%8C-%D8%A7%D8%B2-%D8%B7%D8%B1%D9%81-%D8%B3%D8%B1%D9%88%DB%8C%D8%B3-%D8%AF%D9%87%D9%86%D8%AF%D9%87

https://stackoverflow.com/questions/5195452/websockets-vs-server-sent-events-eventsource/5326159