使用gzip压缩传输JSON数据时Ajax进度停滞问题咨询
Hey there! Let's break down why your large JSON Ajax request is hitting that frustrating mid-progress stall even with gzip compression enabled. I’ve tackled similar issues before, so here are the most likely fixes and explanations:
1. Fix PHP Output Buffering Conflicts
First off, mixing ob_start('ob_gzhandler') and manual header('Content-Encoding: gzip') can cause unexpected behavior. The ob_gzhandler callback automatically adds the Content-Encoding header for you—adding it manually might lead to duplicate headers or compression mismatches that confuse the browser.
Also, check your PHP output buffer size: if it’s too small, PHP will hold onto compressed data until the buffer is full, creating that "stall" while it waits to send anything to the client. Adjust it with:
ini_set('output_buffering', '8192'); // Larger buffer size (adjust as needed) ob_start('ob_gzhandler'); header('Content-Type: application/json'); // Remove the manual Content-Encoding header!
2. Use Chunked Streaming for Progressive Delivery
The biggest reason for stalls is that PHP is probably buffering the entire compressed JSON payload before sending it to the client. For large datasets, switch to chunked transfer encoding to send data in small, incremental chunks—this keeps the progress bar moving smoothly.
Here’s a PHP example for streaming a large JSON dataset:
ob_start('ob_gzhandler'); header('Content-Type: application/json'); header('Transfer-Encoding: chunked'); // Enable chunked streaming // Example: Stream JSON from a database query (avoid loading all data into memory) echo '['; $isFirstRow = true; $stmt = $pdo->prepare('SELECT * FROM large_dataset'); $stmt->execute(); while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { if (!$isFirstRow) echo ','; echo json_encode($row); $isFirstRow = false; // Force buffer to flush immediately ob_flush(); flush(); usleep(50); // Optional: Prevent overwhelming the server } echo ']'; ob_end_flush();
3. Tweak jQuery Ajax for Progress Tracking
Make sure your client-side code is set up to listen for real-time progress events, so you can confirm data is flowing and keep users informed. The default jQuery Ajax setup won’t show incremental progress unless you configure the XHR object explicitly:
$.ajax({ url: '/your-php-endpoint.php', type: 'GET', xhr: function() { const xhr = new XMLHttpRequest(); // Listen for progress updates xhr.addEventListener('progress', (e) => { if (e.lengthComputable) { const progressPercent = (e.loaded / e.total) * 100; console.log(`Request progress: ${progressPercent.toFixed(1)}%`); // Update your UI progress bar here } }); return xhr; }, success: (data) => { // Handle full JSON payload once it's fully received }, cache: false, dataType: 'json' });
4. Avoid Double Compression with Server-Level Gzip
If your web server (Apache/Nginx) already has gzip compression enabled at the server level, using PHP’s ob_gzhandler will cause double-compression—this can corrupt data or lead to unexpected stalls.
- For Apache: Add this to your
.htaccessand remove PHP’s compression code:<IfModule mod_deflate.c> AddOutputFilterByType DEFLATE application/json text/javascript text/css </IfModule> - For Nginx: Enable gzip in your config for JSON content:
gzip on; gzip_types application/json text/javascript text/css;
Server-level compression is often more efficient and avoids conflicts with PHP’s output buffering.
5. Optimize JSON Generation
If you’re building the JSON payload in memory (e.g., collecting all rows into an array before encoding), you’re wasting memory and delaying the start of data transmission. Instead, build and output the JSON incrementally (like the database example above) to reduce memory usage and start sending data faster.
内容的提问来源于stack exchange,提问作者KOUSIK MANDAL

