Sunucu tarafından gönderilen etkinlikler (SSE'ler), HTTP ile bir sunucudan istemciye otomatik güncellemeler gönderir. bağlantı. Bağlantı kurulduktan sonra sunucular verileri başlatabilir iletim.
Web uygulamanızdan push bildirimleri göndermek için SSE'leri kullanabilirsiniz. SSE'ler bilgileri tek bir yönde gönderdiğinden gerekir.
SSE kavramı size tanıdık gelebilir. Web uygulaması "abone olur" akışa sunucu tarafından oluşturulan güncellemeler ve yeni bir etkinlik gerçekleştiğinde bir bildirim gönderilir. Ama sunucu tarafından gönderilen etkinlikleri gerçekten anlamak için önceki AJAX öncülerinin sınırlamalarını anlayın. Bunlardan bazıları:
Anketleme: Uygulama, sunucuyu veriler için sürekli olarak yoklar. Bu teknik AJAX uygulamalarının çoğu tarafından kullanılır. HTTP protokolüyle, istek ve yanıt formatı etrafında şekillenir. İstemci bir istek gönderir ve sunucunun verilerle yanıt vermesini bekler. Yoksa, boş bir hatası döndürülür. Ekstra yoklama, daha fazla HTTP ek yükü oluşturur.
Uzun yoklama (Asılı GET / COMET): Sunucuda veri yoksa kullanılabilir durumdaysa sunucu, yeni veriler gelene kadar isteği açık tutar. Dolayısıyla, bu teknik genellikle "Asılı GET" olarak adlandırılır. Zaman sunucu yanıt verir, bağlantıyı kapatır ve ve süreç tekrarlanır. Bu nedenle, sunucu sürekli olarak yeni veriler oluşturabilirsiniz. Geliştiriciler bunu ayarlamak için genellikle komut dosyası etiketlerini bir 'sonsuz' iframe'dir.
Sunucu tarafından gönderilen etkinlikler, baştan sona verimli olacak şekilde tasarlanmıştır. SSE'lerle iletişim kurarken bir sunucu, SSE'lerinize veri ve uygulamayı ilk kez istekte bulunmaya gerek kalmadan uygulamaya aktarabilirsiniz. Başka bir deyişle, güncellemeler gerçekleştikçe sunucudan istemciye aktarılabilir. SSE'ler Sunucu ve istemci arasında tek bir tek yönlü kanal açmak.
Sunucu tarafından gönderilen etkinlikler ile uzun anket arasındaki temel fark, SSE'lerin doğrudan tarayıcı tarafından işlenir ve kullanıcının yalnızca iletileri dinlemesi gerekir.
Sunucu tarafından gönderilen etkinlikler ile WebSocket'lerin karşılaştırılması
Neden WebSockets yerine sunucu tarafından gönderilen etkinlikleri tercih edersiniz? Güzel soru.
WebSockets, aşağıdakileri içeren zengin bir protokole sahiptir: iki yönlü, tam çift yönlü iletişim. İki yönlü bir kanal, Google Play Games Beta ile neredeyse gerçek zamanlı güncellemelere ihtiyaç duyduğunuz sağlayabilirsiniz.
Ancak bazen bir sunucudan yalnızca tek yönlü iletişime ihtiyacınız olur.
Örneğin, bir arkadaşınız durumunu, hisse senedi borsalarını, haber feed'lerini veya
diğer otomatik veri aktarma mekanizmalarını kullanabilirsiniz. Başka bir deyişle,
istemci tarafında yapılan Web SQL Veritabanı veya IndexedDB nesne deposu güncellemesi.
Bir sunucuya veri göndermeniz gerekiyorsa, XMLHttpRequest
her zaman arkadaşınızdır.
SSE'ler HTTP üzerinden gönderilir. Özel bir protokol veya sunucu yoktur uygulamaya karar vermemiz gerekir. WebSocket'ler tam çift yönlü gerektirir bağlantıları ve yeni WebSocket sunucularıyla çalışır.
Buna ek olarak, sunucu tarafından gönderilen etkinlikler WebSocket'lerde bulunmayan çeşitli özelliklere sahiptir ve otomatik olarak yeniden bağlanma, etkinlik kimlikleri ve isteğe bağlıdır.
JavaScript ile EventSource oluşturma
Bir etkinlik akışına abone olmak için EventSource
nesnesi oluşturun ve bunu
Akışınızın URL'si:
const source = new EventSource('stream.php');
Sonra, message
etkinliği için bir işleyici ayarlayın. İsterseniz
open
ve error
dinle:
source.addEventListener('message', (e) => {
console.log(e.data);
});
source.addEventListener('open', (e) => {
// Connection was opened.
});
source.addEventListener('error', (e) => {
if (e.readyState == EventSource.CLOSED) {
// Connection was closed.
}
});
Güncellemeler sunucudan aktarıldığında onmessage
işleyicisi etkinleşir
ve e.data
mülkünde yeni veriler var. İşin sihirli kısmı
bağlantı her kapatıldığında tarayıcının otomatik olarak
kaynağı. Sunucu uygulamanız,
hakkında daha fazla bilgi edinin.
Bu kadar basit. Müşteriniz artık stream.php
takvimindeki etkinlikleri işleyebilir.
Etkinlik akışı biçimi
Kaynağından bir etkinlik akışı göndermek,
text/event-stream
İçerik Türü ile sunulan düz metin yanıtı,
şu SSE biçimine uyar.
Yanıt, temel biçiminde bir data:
satırı ve onu takip eden bir
mesajı ve ardından iki "\n" karakteri ekleyin:
data: My message\n\n
Çok satırlı veriler
Mesajınız daha uzunsa birden fazla data:
satırı kullanarak bölebilirsiniz.
data:
ile başlayan iki veya daha fazla ardışık satır, karakter olarak kabul edilir
tek bir veri parçasına sahip olduğundan yalnızca bir message
etkinliği tetiklenir.
Her satır tek bir "\n" ile sona ermelidir (sonun olması gereken sonuncu
(iki ile birlikte). message
işleyicinize iletilen sonuç tek bir dizedir
yeni satır karakterleriyle birleştirilir. Örneğin:
data: first line\n
data: second line\n\n</pre>
Bu, "ilk satır\nikinci satırı" oluşturur e.data
içinde. Bir kullanıcı daha sonra
"\n" sans mesajını yeniden oluşturmak için e.data.split('\n').join('')
karakteri ekleyin.
JSON verilerini gönder
Birden çok satır kullanmak, söz dizimini bozmadan JSON göndermenize yardımcı olur:
data: {\n
data: "msg": "hello world",\n
data: "id": 12345\n
data: }\n\n
Ayrıca, bu akışı işlemek için olası istemci tarafı kodu:
source.addEventListener('message', (e) => {
const data = JSON.parse(e.data);
console.log(data.id, data.msg);
});
Bir etkinlikle kimliği ilişkilendirme
Şu şekilde başlayan bir satır ekleyerek akış etkinliğiyle benzersiz bir kimlik gönderebilirsiniz:
id:
:
id: 12345\n
data: GOOG\n
data: 556\n\n
Bir kimlik ayarlamak, tarayıcının tetiklenen son etkinliği izlemesini sağlar. Böylece
bağlantı kesilirse, özel bir HTTP üstbilgisi (Last-Event-ID
)
yeni istekle ayarlanır. Bu sayede tarayıcı, hangi etkinliğin tetiklenmek için uygun olduğunu belirleyebilir.
message
etkinliği, bir e.lastEventId
özelliği içerir.
Yeniden bağlanma zaman aşımını kontrol etme
Tarayıcı yaklaşık 3 saniye içinde kaynağa yeniden bağlanmayı dener
her bağlantı kapatıldıktan sonra gelir. Bu zaman aşımı süresini
retry:
ile başlayan ve ardından milisaniye sayısı ile devam eden satır
bağlanmayı denemeden önce bekleyin.
Aşağıdaki örnekte, 10 saniye sonra yeniden bağlanma teşebbüsünde bulunulmuştur:
retry: 10000\n
data: hello world\n\n
Bir etkinlik adı belirtin
Tek bir etkinlik kaynağı, aşağıdakileri yaparak farklı türlerde etkinlikler oluşturabilir:
etkinlik adı. event:
ile başlayan bir satır varsa
ve ardından etkinlik için benzersiz bir ad girerseniz etkinlik bu adla ilişkilendirilir.
İstemcide, söz konusu etkinliği dinleyecek bir etkinlik işleyici ayarlanabilir.
Örneğin, aşağıdaki sunucu çıkışı üç tür etkinlik gönderir: genel bir "mesaj" event, "userlogon" ve "update" etkinlik:
data: {"msg": "First message"}\n\n
event: userlogon\n
data: {"username": "John123"}\n\n
event: update\n
data: {"username": "John123", "emotion": "happy"}\n\n
İstemcide etkinlik işleyiciler ayarlandığında:
source.addEventListener('message', (e) => {
const data = JSON.parse(e.data);
console.log(data.msg);
});
source.addEventListener('userlogon', (e) => {
const data = JSON.parse(e.data);
console.log(`User login: ${data.username}`);
});
source.addEventListener('update', (e) => {
const data = JSON.parse(e.data);
console.log(`${data.username} is now ${data.emotion}`);
};
Sunucu örnekleri
Aşağıda, PHP'deki temel bir sunucu uygulaması verilmiştir:
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache'); // recommended to prevent caching of event data.
/**
* Constructs the SSE data format and flushes that data to the client.
*
* @param string $id Timestamp/id of this connection.
* @param string $msg Line of text that should be transmitted.
**/
function sendMsg($id, $msg) {
echo "id: $id" . PHP_EOL;
echo "data: $msg" . PHP_EOL;
echo PHP_EOL;
ob_flush();
flush();
}
$serverTime = time();
sendMsg($serverTime, 'server time: ' . date("h:i:s", time()));
?>
Aşağıda, Node JS kullanılarak Ekspres işleyici:
app.get('/events', (req, res) => {
// Send the SSE header.
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
// Sends an event to the client where the data is the current date,
// then schedules the event to happen again after 5 seconds.
const sendEvent = () => {
const data = (new Date()).toLocaleTimeString();
res.write("data: " + data + '\n\n');
setTimeout(sendEvent, 5000);
};
// Send the initial event immediately.
sendEvent();
});
sse-node.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
</head>
<body>
<script>
const source = new EventSource('/events');
source.onmessage = (e) => {
const content = document.createElement('div');
content.textContent = e.data;
document.body.append(content);
};
</script>
</body>
</html>
Etkinlik akışını iptal etme
Normalde, bağlantı kurulduğunda tarayıcı etkinlik kaynağına otomatik olarak yeniden bağlanır. kapalıdır, ancak bu davranış istemci veya sunucudan iptal edilebilir.
İstemciden canlı yayını iptal etmek için şu numarayı arayın:
source.close();
Sunucudan bir akışı iptal etmek için text/event-stream
dışında bir seçenekle yanıt verin.
Content-Type
veya 200 OK
dışında bir HTTP durumu döndür
(ör. 404 Not Found
).
Her iki yöntem de tarayıcının bağlantıyı yeniden kurmasını engeller.
Güvenlikle ilgili söz
EventSource tarafından oluşturulan istekler getirme gibi diğer ağ API'lerini kullanabilir. Sunucunuzda SSE uç noktasına ihtiyacınız varsa daha fazla bilgi edinmek istiyorsanız, Kaynaklar Arası Kaynak Paylaşımı (CORS).