Good day to everybody,
I am new to this forum but will try to do my best to follow the rules. I am currently working on a better solution to have a progress bar when sending an Ajax request that handles a Gzip response.
For this to work, we need lengthComputable, and, unfortunately, when using header("Content-Encoding: gzip") in PHP, the Content-Length cannot be set.
In order to achieve it, I am using this code but I am encountering an issue in ajax as, even if I receive a 200 OK status code, the ajax is considered as failed and I have to do the callback inside the fail.
It s working very well, pako is very fast, but only across the ajax fail.
I am using:
- https://github.com/nodeca/pako (pako to handle the ungzip).
- Convert integer array to string at javascript (utf8 decodeURIComponent)
Thank you in advance for your help
javascript code:
//-----------------------------------
// ajax progress listener method
//-----------------------------------
!function (e) {
"function" == typeof define && define.amd ? define(["jquery"], e) : "object"
== typeof exports ? module.exports = e(require("jquery")) : e(jQuery)
}(function (e) {
var n = e.ajax.bind(e);
e.ajax = function (r, t) {
"object" == typeof r && (t = r, r = void 0), t = t || {};
var o;
o = t.xhr ? t.xhr() : e.ajaxSettings.xhr(), t.xhr = function () {
return o
};
var s = t.chunking || e.ajaxSettings.chunking;
o.upload.onprogress = null;
var i = n(r, t);
return i.progress = function (e) {
var n = 0;
return o.addEventListener("progress", function (r) {
var t = [r], o = "";
3 == this.readyState && s && (o = this.responseText.substr(n), n
= this.responseText.length, t.push(o)), e.apply(this, t)
}, !1), this
}, i.uploadProgress = function (e) {
return o.upload && o.upload.addEventListener("progress", function
(n) {
e.apply(this, [n])
}, !1), this
}, i
}
});
//-----------------------------------
// atos decodeURIComponent for UTF8
//-----------------------------------
function decodeURI(arr) {
for (var i = 0, l = arr.length, s = '', c; c = arr[i++]; )
s += String.fromCharCode(
c > 0xdf && c < 0xf0 && i < l - 1
? (c & 0xf) << 12 | (arr[i++] & 0x3f) << 6 | arr[i++] & 0x3f
: c > 0x7f && i < l
? (c & 0x1f) << 6 | arr[i++] & 0x3f
: c
);
return s
}
//-----------------------------------
// ajax request
//-----------------------------------
let progressBar = document.querySelector(".progress");
const request = $.ajax({
type: "GET",
url: 'test.php',
dataType: 'json',
cache: false,
data: JSON.stringify({test:true}),
async: true
}).progress(function (e) {
if (e.lengthComputable) {
progressBar.style.width = Math.round((e.loaded * 100) / e.total) + "%";
}
});
request.done(response => {
console.log('no success despite 200 OK');
const result = JSON.parse(decodeURI(pako.ungzip(atob(response))));
parseJson(result);
}).fail(response => {
parseJsonerror()
});
function parseJson(result) {
/* do stuff */
}
function parseJsonerror(){
/* any error */
}
PHP code:
<?PHP
header('Connection: Keep-Alive');
header("Content-Type: application/json");
/*do stuff*/
$result = json_encode($stuff);
$result64 = base64_encode(gzdeflate($result, 6, ZLIB_ENCODING_DEFLATE));
header("Content-Length:" . mb_strlen($result_list));
echo $result64;
UPDATE
I will answer my own question. Found out the obvious: dataType: "json" in ajax needs to be taken out.
and in PHP: header("Content-type: text/html ; charset=utf-8"); instead of header("Content-Type: application/json");
So this method works wonderfully to have a working progress bar in ajax and keeping a gZip content. Despite the added code in javascript pako and the utf8 decodeURIComponent function are very fast.
to be noted :using this method, content size is 50% smaller than the browser auto gzip method with php header("Content-Encoding: gzip").
Thank you for reading.