É mais simples do que eu pensava inicialmente. Basicamente, você tem uma página que não faz nada, até que os dados que você deseja enviar estejam disponíveis (por exemplo, uma nova mensagem chega).
Aqui está um exemplo realmente básico, que envia uma sequência simples após 2-10 segundos. 1 em 3 chances de retornar um erro 404 (para mostrar o tratamento de erros no próximo exemplo de 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));
?>
Nota: Em um site real, a execução em um servidor Web comum como o Apache rapidamente amarra todos os "threads de trabalho" e deixa-o incapaz de responder a outras solicitações. Existem maneiras de contornar isso, mas é recomendável escrever um "servidor de pesquisa longa" em algo como o twisted do Python , que não depende de um thread por solicitação. O cometD é popular (disponível em vários idiomas), e o Tornado é uma nova estrutura criada especificamente para essas tarefas (foi criada para o longo código de pesquisa do FriendFeed) ... mas como um exemplo simples, o Apache é mais do que adequado ! Esse script pode ser facilmente escrito em qualquer idioma (eu escolhi o Apache / PHP, pois eles são muito comuns, e eu os estava executando localmente)
Em Javascript, você solicita o arquivo acima ( msg_srv.php
) e aguarda uma resposta. Quando você obtém um, você age com base nos dados. Então você solicita o arquivo e espera novamente, age com base nos dados (e repita)
A seguir, é apresentado um exemplo dessa página. Quando a página é carregada, ela envia a solicitação inicial para o msgsrv.php
arquivo. Se for bem-sucedida, anexamos a mensagem à #messages
div e, após 1 segundo, chamamos a função waitForMsg novamente, o que desencadeia a espera.
O segundo setTimeout()
é um limitador de taxa realmente básico, funciona bem sem isso, mas se msgsrv.php
sempre retorna instantaneamente (com um erro de sintaxe, por exemplo) - você inunda o navegador e pode congelar rapidamente. É melhor verificar se o arquivo contém uma resposta JSON válida e / ou manter um total em execução de solicitações por minuto / segundo e fazer uma pausa apropriada.
Se a página cometer erros, ele anexa o erro à #messages
div, aguarda 15 segundos e tenta novamente (idêntico ao modo como esperamos 1 segundo após cada mensagem)
O bom dessa abordagem é que ela é muito resistente. Se a conexão com a Internet dos clientes morrer, o tempo limite será excedido e, em seguida, tente se reconectar - isso é inerente ao tempo em que a pesquisa funciona, sem a necessidade de tratamento de erros complicado.
De qualquer forma, o long_poller.htm
código, usando a estrutura 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>