82 votes

jquery ajax, lire le flux de manière incrémentielle?

J'ai lu cette question , mais il n'est pas exactement la réponse à ma question. Malheureusement, il semble que les choses ont changé dans la XHR objet depuis la dernière fois que j'ai regardé Ajax, donc il n'est plus possible d'accéder directement à des responseText avant qu'il est fini d'être rempli.
Je dois écrire une page qui utilise AJAX (de préférence jQuery, mais je suis ouvert aux suggestions) pour récupérer des données au format CSV via HTTP à partir d'un serveur, je n'ai aucun contrôle sur. Les données de réponse pourrait être assez important; un mégaoctet de texte n'est pas rare.
Le serveur est stream de l'environnement. Est-il encore un moyen d'obtenir l'accès à un flux de données qu'il est retourné, directement à partir de Javascript?
J'ai la possibilité d'écrire du code PHP qui vit dans le milieu et utilise une sorte de "Comète" tech (le long du scrutin, EventSource, etc), mais je préfère éviter si possible.

Dans le cas où il est pertinent, pour assumer cette question que les utilisateurs disposent de la dernière version de Firefox/Chrome/Opéra et de la vieille compatibilité de votre navigateur n'est pas un problème.

96voto

AlexMorley-Finch Points 1498

J'ai abordé cette question et a trouvé quelques vilains bugs que les gens peuvent trouver utile!

Une solution à l'aide du texte/html est simple...

FICHIER PHP

header('Content-type: text/html; charset=utf-8');
function output($val)
{
    echo $val;
    flush();
    ob_flush();
    usleep(500000);
}
output('Begin... (counting to 10)');
for( $i = 0 ; $i < 10 ; $i++ )
{
    output($i+1);
}
output('End...');

FICHIER HTML

<!DOCTYPE>
<html>
    <head>
        <title>Flushed ajax test</title>
        <meta charset="UTF-8" />
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    </head>
    <body>
        <script type="text/javascript">
        var last_response_len = false;
        $.ajax('./flushed-ajax.php', {
            xhrFields: {
                onprogress: function(e)
                {
                    var this_response, response = e.currentTarget.response;
                    if(last_response_len === false)
                    {
                        this_response = response;
                        last_response_len = response.length;
                    }
                    else
                    {
                        this_response = response.substring(last_response_len);
                        last_response_len = response.length;
                    }
                    console.log(this_response);
                }
            }
        })
        .done(function(data)
        {
            console.log('Complete response = ' + data);
        })
        .fail(function(data)
        {
            console.log('Error: ', data);
        });
        console.log('Request Sent');
        </script>
    </body>
</html>

La modification de ce code en ajax est exactement le même.

Modifier le FICHIER PHP correspondant à la ligne 4 de echo $val; de echo '{"name":"'.$val.'"};'

Changement de FICHIER HTML, ligne 24 console.log(this_response); de

this_response = JSON.parse(this_response);
console.log(this_response.name);

Cela bien que le code s'affiche bien, et TOUT ce que nous avons fait, c'est enveloppée JSON autour d'une variable, il est plus complcated que cela.

Pour le long temps j'ai changé mon en-tête de application/json

Cependant, c'est le bug qui m'a fait une recherche sur google pendant 3 jours.

Lorsque la réponse est de type application/json, lorsque la réaction est COMPLÈTE, entièrement terminée. La réponse complète est tenté de analysée, pour vérifier s'il est en effet json.

Hovever notre réponse COMPLÈTE est {/bla json/}{/bla json/}{/bla json/}

Ce qui n'est PAS valide JSON

par conséquent, l' jqXHR.done méthode suppose, il y avait une erreur, car la réponse complète ne peut pas être analysée comme JSON.

DONC, SI VOUS VOULEZ JSON DE TELS PROGRÈS

NE PAS DÉFINIR LE TYPE D'APPLICATION EN JSON!

Espérons que certaines personnes trouvent cela utile

34voto

Petah Points 18432

Utilisation XMLHttpRequest.js

https://github.com/ilinsky/xmlhttprequest

http://code.google.com/p/xmlhttprequest

  • Offre discret, respectueux des standards (W3C) de la croix-navigateur de mise en œuvre de la 1.0 l'objet XMLHttpRequest
  • Résout TOUS les navigateurs bizarreries observés dans leur propre objet XMLHttpRequest implémentations
  • Permet transparent journalisation de l'objet XMLHttpRequest activité

L'utilisation de longues interrogation avec PHP:

output.php:

<?php
header('Content-type: application/octet-stream');

// Turn off output buffering
ini_set('output_buffering', 'off');
// Turn off PHP output compression
ini_set('zlib.output_compression', false);
// Implicitly flush the buffer(s)
ini_set('implicit_flush', true);
ob_implicit_flush(true);
// Clear, and turn off output buffering
while (ob_get_level() > 0) {
    // Get the curent level
    $level = ob_get_level();
    // End the buffering
    ob_end_clean();
    // If the current level has not changed, abort
    if (ob_get_level() == $level) break;
}
// Disable apache output buffering/compression
if (function_exists('apache_setenv')) {
    apache_setenv('no-gzip', '1');
    apache_setenv('dont-vary', '1');
}

// Count to 20, outputting each second
for ($i = 0;$i < 20; $i++) {
    echo $i.str_repeat(' ', 2048).PHP_EOL;
    flush();
    sleep(1);
}

run.php:

<script src="http://code.jquery.com/jquery-1.6.4.js"></script>
<script src="https://raw.github.com/ilinsky/xmlhttprequest/master/XMLHttpRequest.js"></script>

<script>
$(function() {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', '/longpoll/', true);
    xhr.send(null);
    var timer;
    timer = window.setInterval(function() {
        if (xhr.readyState == XMLHttpRequest.DONE) {
            window.clearTimeout(timer);
            $('body').append('done <br />');
        }
        $('body').append('state: ' + xhr.readyState + '<br />');
        console.log(xhr.responseText);
        $('body').append('data: ' + xhr.responseText + '<br />');
    }, 1000);
});
</script>

Cela devrait de sortie:

state: 3
data: 0
state: 3
data: 0 1
state: 3
data: 0 1 2
state: 3
data: 0 1 2 3
state: 3
data: 0 1 2 3 4
...
...
...
state: 3
data: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
state: 3
data: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
state: 3
data: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
done
state: 4
data: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 

Pour IE, vous devez regarder dans XDomainRequest

http://blogs.msdn.com/b/ieinternals/archive/2010/04/06/comet-streaming-in-internet-explorer-with-xmlhttprequest-and-xdomainrequest.aspx

http://msdn.microsoft.com/en-us/library/cc288060(SV.85).aspx

21voto

Hexxagonal Points 6187

Vous allez avoir à utiliser directement en haut du javascript pour ça. La raison en est que vous allez avoir à interroger en permanence et de ne pas attendre pour les rappels à feu. Vous n'avez pas besoin de jQuery pour cela, c'est assez simple. Ils ont une belle de code source pour l'Ajax Modèles de site web.

Essentiellement, vous aurez juste envie de garder une trace de votre dernière position dans la réponse et interroger périodiquement pour plus de texte passé de cet emplacement. La différence dans votre cas, c'est que vous pouvez vous abonner à l'événement et d'arrêter votre bureau de vote.

16voto

g19fanatic Points 3506

Puisque vous dites que votre serveur est stream amical (asynchrone) et était à la recherche de jquery solution, avez-vous vérifié le jQuery Flux de Plugin?

Il est vraiment facile à utiliser et il vous permet de ne pas vraiment vous soucier de quoi que ce soit. Il a assez bonne documentation .

-1voto

Ashik Basheer Points 100

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X