To prostsze niż początkowo myślałem. Zasadniczo masz stronę, która nic nie robi, dopóki dane, które chcesz wysłać, nie będą dostępne (powiedzmy, że przybywa nowa wiadomość).
Oto naprawdę prosty przykład, który wysyła prosty ciąg znaków po 2-10 sekundach. 1 na 3 szanse na zwrócenie błędu 404 (aby pokazać obsługę błędów w nadchodzącym przykładzie Javascript)
msgsrv.php
<?php
if(rand(1,3) == 1){
/* Fake an error */
header("HTTP/1.0 404 Not Found");
die();
}
/* Send a string after a random number of seconds (2-10) */
sleep(rand(2,10));
echo("Hi! Have a random number: " . rand(1,10));
?>
Uwaga: w prawdziwej witrynie uruchomienie tego na zwykłym serwerze internetowym, takim jak Apache, spowoduje szybkie powiązanie wszystkich „wątków roboczych” i nie będzie w stanie odpowiedzieć na inne żądania. Można to zrobić na wiele sposobów, ale zaleca się napisanie „serwer długiego odpytywania” w czymś w rodzaju skręconego Pythona , który nie polega na jednym wątku na żądanie. cometD jest popularny (dostępny w kilku językach), a Tornado to nowa platforma stworzona specjalnie do takich zadań (została zbudowana dla długiego odpytywania FriendFeed) ... ale jako prosty przykład Apache jest więcej niż wystarczający ! Skrypt ten można łatwo napisać w dowolnym języku (wybrałem Apache / PHP, ponieważ są one bardzo popularne i zdarzyło mi się uruchamiać je lokalnie)
Następnie w Javascripcie żądasz powyższego pliku ( msg_srv.php
) i czekasz na odpowiedź. Kiedy je otrzymasz, działasz na podstawie danych. Następnie żądasz pliku i czekasz ponownie, działasz na podstawie danych (i powtórz)
Poniżej znajduje się przykład takiej strony. Gdy strona zostanie załadowana, wysyła początkowe żądanie msgsrv.php
pliku. Jeśli się powiedzie, dołączamy wiadomość do #messages
div, a następnie po 1 sekundzie ponownie wywołujemy funkcję waitForMsg, co powoduje oczekiwanie.
1 sekunda setTimeout()
jest naprawdę podstawowym ogranicznikiem szybkości, bez niej działa dobrze, ale jeśli msgsrv.php
zawsze wraca natychmiast (na przykład z błędem składni) - zalewasz przeglądarkę i może się szybko zawiesić. Lepiej byłoby to zrobić sprawdzając, czy plik zawiera prawidłową odpowiedź JSON i / lub utrzymując bieżącą liczbę żądań na minutę / sekundę i odpowiednio zatrzymując.
Jeśli strona popełni błąd, dołącza błąd do #messages
div, czeka 15 sekund, a następnie próbuje ponownie (identycznie, jak czekamy 1 sekundę po każdej wiadomości)
Zaletą tego podejścia jest to, że jest bardzo odporny. Jeśli połączenie internetowe klienta zostanie przerwane, nastąpi przekroczenie limitu czasu, a następnie spróbuj ponownie nawiązać połączenie - jest to nieodłączne od czasu działania odpytywania, nie jest wymagana skomplikowana obsługa błędów
W każdym razie long_poller.htm
kod, używając frameworka jQuery:
<html>
<head>
<title>BargePoller</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<style type="text/css" media="screen">
body{ background:#000;color:#fff;font-size:.9em; }
.msg{ background:#aaa;padding:.2em; border-bottom:1px #000 solid}
.old{ background-color:#246499;}
.new{ background-color:#3B9957;}
.error{ background-color:#992E36;}
</style>
<script type="text/javascript" charset="utf-8">
function addmsg(type, msg){
/* Simple helper to add a div.
type is the name of a CSS class (old/new/error).
msg is the contents of the div */
$("#messages").append(
"<div class='msg "+ type +"'>"+ msg +"</div>"
);
}
function waitForMsg(){
/* This requests the url "msgsrv.php"
When it complete (or errors)*/
$.ajax({
type: "GET",
url: "msgsrv.php",
async: true, /* If set to non-async, browser shows page as "Loading.."*/
cache: false,
timeout:50000, /* Timeout in ms */
success: function(data){ /* called when request to barge.php completes */
addmsg("new", data); /* Add response to a .msg div (with the "new" class)*/
setTimeout(
waitForMsg, /* Request next message */
1000 /* ..after 1 seconds */
);
},
error: function(XMLHttpRequest, textStatus, errorThrown){
addmsg("error", textStatus + " (" + errorThrown + ")");
setTimeout(
waitForMsg, /* Try again after.. */
15000); /* milliseconds (15seconds) */
}
});
};
$(document).ready(function(){
waitForMsg(); /* Start the inital request */
});
</script>
</head>
<body>
<div id="messages">
<div class="msg old">
BargePoll message requester!
</div>
</div>
</body>
</html>