Ich habe diese Frage gelesen , aber sie beantwortet meine Frage nicht genau. Leider sieht es so aus, als hätten sich die Dinge im XHR-Objekt geändert, seit ich AJAX das letzte Mal angesehen habe. Daher ist es nicht mehr möglich, direkt darauf zuzugreifen, responseText
bevor das Auffüllen abgeschlossen ist.
Ich muss eine Seite schreiben, die AJAX verwendet (vorzugsweise jQuery, aber ich bin offen für Vorschläge), um CSV-Daten über HTTP von einem Server abzurufen, über den ich keine Kontrolle habe. Die Antwortdaten können sehr groß sein. Ein Megabyte Text ist keine Seltenheit.
Der Server ist streamfreundlich. Gibt es noch eine Möglichkeit, direkt aus JavaScript auf einen Datenstrom zuzugreifen, wenn dieser zurückgegeben wird?
Ich habe die Möglichkeit, PHP-Code zu schreiben, der in der Mitte lebt und eine Art "Comet" -Technologie verwendet (Long-Polling, EventSource usw.), aber ich würde es vorziehen, dies nach Möglichkeit zu vermeiden.
Nehmen Sie für diese Frage an, dass Benutzer über die neueste Version von Firefox / Chrome / Opera verfügen und die Kompatibilität mit alten Browsern kein Problem darstellt.
Antworten:
Sie werden dafür direkt Javascript verwenden wollen. Der Grund dafür ist, dass Sie kontinuierlich abfragen und nicht darauf warten möchten, dass die Rückrufe ausgelöst werden. Sie brauchen dafür kein jQuery, es ist ziemlich einfach. Sie haben einen schönen Quellcode dafür auf der Ajax Patterns-Website .
Im Wesentlichen möchten Sie nur Ihre letzte Position in der Antwort verfolgen und regelmäßig nach mehr Text über diesen Speicherort hinaus abfragen. Der Unterschied in Ihrem Fall besteht darin, dass Sie das gesamte Ereignis abonnieren und Ihre Umfrage beenden können.
quelle
Dies ist bei der Ausgabe von Text oder HTML recht einfach . Unten ist ein Beispiel.
(Sie werden jedoch auf Probleme stoßen, wenn Sie versuchen, JSON auszugeben , die ich weiter unten angehen werde.)
PHP-DATEI
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...');
HTML-DATEI
<!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>
Was ist, wenn ich dies mit JSON tun muss?
Es ist nicht möglich, ein einzelnes JSON-Objekt inkrementell zu laden (bevor es vollständig geladen ist), da die Syntax immer ungültig ist, bis Sie das vollständige Objekt haben.
Wenn Ihre Antwort jedoch mehrere JSON-Objekte nacheinander enthält, können Sie eines nach dem anderen laden, sobald sie die Pipe durchlaufen.
Also habe ich meinen Code oben um ...
Ändern von PHP FILE Zeile 4 von
echo $val;
nachecho '{"name":"'.$val.'"};'
. Dies gibt eine Reihe von JSON-Objekten aus.Ändern der HTML-DATEI-Zeile 24 von
console.log(this_response);
nachthis_response = JSON.parse(this_response); console.log(this_response.name);
Beachten Sie, dass dieser rudimentäre Code davon ausgeht, dass jeder "Brocken", der in den Browser gelangt, ein gültiges JSON-Objekt ist. Dies ist nicht immer der Fall, da Sie nicht vorhersagen können, wie Pakete ankommen werden. Möglicherweise müssen Sie die Zeichenfolge anhand von Semikolons aufteilen (oder ein anderes Trennzeichen erstellen).
Nicht benutzen
application/json
Do NOT Für Änderung Ihrer Header
application/json
- Ich tat dies , und es hatte mich für 3 Tage googeln. Wenn der Antworttyp lautetapplication/json
, wartet der Browser, bis die Antwort vollständig ist. Die vollständige Antwort wird dann analysiert, um zu überprüfen, ob es sich um infaktes JSON handelt. Unsere vollständige Antwort lautet{...};{...};{...};
jedoch NICHT JSON. DiejqXHR.done
Methode geht davon aus, dass ein Fehler aufgetreten ist, da die vollständige Antwort nicht als JSON analysiert werden kann.Wie in den Kommentaren erwähnt, können Sie diese Prüfung auf der Clientseite deaktivieren, indem Sie Folgendes verwenden:
$.ajax(..., {dataType: "text"})
Hoffe, einige Leute finden das nützlich.
quelle
echo '{"name":"'.$val.'"};'
) verkettet werden . Ein besserer Code könnte seinecho json_encode(["name"=>$val]).";";
.Verwenden Sie XMLHttpRequest.js
https://github.com/ilinsky/xmlhttprequest
http://code.google.com/p/xmlhttprequest
So verwenden Sie lange Abfragen mit 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>
Dies sollte Folgendes ausgeben:
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
Für IE müssen Sie in XDomainRequest schauen
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(VS.85).aspx
quelle
application/octet-stream
. In meinem aktualisierten Beitrag finden Sie ein PHP-Beispiel.;
.Haben Sie das jQuery Stream Plugin überprüft, da Sie sagen, Ihr Server ist streamfreundlich (asynchron) und nach einer jquery-Lösung gesucht hat ?
Es ist wirklich einfach zu bedienen und ermöglicht es Ihnen, sich über nichts wirklich Sorgen zu machen. Es hat ziemlich gut Dokumentation .
quelle
Hier ist eine einfache Möglichkeit, dies mit JQuery zu erreichen (wie vom OP angefordert):
Erweitern Sie zunächst das Ajax-Objekt, um onreadystatechange zu unterstützen, indem Sie den folgenden Code unter https://gist.github.com/chrishow/3023092 ausführen (am Ende dieser Antwort angehängt). Rufen Sie dann einfach Ajax mit einer Funktion onreadystatechange auf, die xhr.responseText auf neuen Text überprüft.
Wenn Sie noch schicker werden möchten, können Sie die responseText-Daten jedes Mal löschen, wenn Sie sie lesen (wie hier beschrieben ).
Siehe beispielsweise https://jsfiddle.net/g1jmwcmw/1/ , in dem die Antwort von https://code.jquery.com/jquery-1.5.js heruntergeladen und in Blöcken in Ihrem Konsolenfenster ausgegeben wird Code unten (den Sie einfach in eine HTML-Seite kopieren und dann in Ihrem Browser öffnen können):
<!-- jquery >= 1.5. maybe earlier too but not sure --> <script src=https://code.jquery.com/jquery-1.5.min.js></script> <script> /* One-time setup (run once before other code) * adds onreadystatechange to $.ajax options * from https://gist.github.com/chrishow/3023092) * success etc will still fire if provided */ $.ajaxPrefilter(function( options, originalOptions, jqXHR ) { if ( options.onreadystatechange ) { var xhrFactory = options.xhr; options.xhr = function() { var xhr = xhrFactory.apply( this, arguments ); function handler() { options.onreadystatechange( xhr, jqXHR ); } if ( xhr.addEventListener ) { xhr.addEventListener( "readystatechange", handler, false ); } else { setTimeout( function() { var internal = xhr.onreadystatechange; if ( internal ) { xhr.onreadystatechange = function() { handler(); internal.apply( this, arguments ); }; } }, 0 ); } return xhr; }; } }); // ----- myReadyStateChange(): this will do my incremental processing ----- var last_start = 0; // using global var for over-simplified example function myReadyStateChange(xhr /*, jqxhr */) { if(xhr.readyState >= 3 && xhr.responseText.length > last_start) { var chunk = xhr.responseText.slice(last_start); alert('Got chunk: ' + chunk); console.log('Got chunk: ', chunk); last_start += chunk.length; } } // ----- call my url and process response incrementally ----- last_start = 0; $.ajax({ url: "https://code.jquery.com/jquery-1.5.js", // whatever your target url is goes here onreadystatechange: myReadyStateChange }); </script>
quelle
Ich musste ein Grid mit einer großen JSON-Nutzlast versorgen, die immer wieder die maximal zulässige Größenbeschränkung erreichte. Ich habe MVC und jquery verwendet und daher die obige Lösung von AlexMorley-Finch angepasst.
Der Servercode stammt aus "Streaming-Daten mit Web-API" . Auch https://github.com/DblV/StreamingWebApi .
public class StreamingController : ApiController { [HttpGet] [ActionName("GetGridDataStream")] public HttpResponseMessage GetGridDataStream(string id) { var response = Request.CreateResponse(); DynamicData newData = new DynamicData(); var res = newData.GetDataRows(id); response.Content = new PushStreamContent((stream, content, context) => { foreach (var record in res) { var serializer = new JsonSerializer(); using (var writer = new StreamWriter(stream)) { serializer.Serialize(writer, record); stream.Flush(); } // Thread.Sleep(100); } stream.Close(); }); return response; } }
Dadurch wurde ein Stream von {json object} {json object} {json object} erstellt, bei dem Kommas und umgebende [] begrenzt werden mussten, um erfolgreich als json analysiert zu werden.
Dem Client-Code wurden die fehlenden Zeichen folgendermaßen geliefert:
var jsonData = {}; $.ajax("api/Streaming/GetGridDataStream/" + viewName, { xhrFields: { onprogress: function (e) { // console.log(this_response); } } }, { dataType: "text" }) //<== this is important for JSON data .done(function (data) { data = "[" + data.replace(/\}\{/gi, "},{") + "]"; jsonData["DataList"] = JSON.parse(data); //more code follows to create grid }) .fail(function (data) { console.log('Error: ', data); });
Ich hoffe, dies hilft jemandem, der .Net MVC und jQuery verwendet.
quelle