How can I use deflated/gzipped content with an XHR onProgress function?

前端 未结 8 2381
醉酒成梦
醉酒成梦 2020-12-08 00:11

I\'ve seen a bunch of similar questions to this get asked before, but I haven\'t found one that describes my current problem exactly, so here goes:

I have a page whi

8条回答
  •  无人及你
    2020-12-08 00:51

    I wasn't able to solve the issue of using onProgress on the compressed content itself, but I came up with this semi-simple workaround. In a nutshell: send a HEAD request to the server at the same time as a GET request, and render the progress bar once there's enough information to do so.


    function loader(onDone, onProgress, url, data)
    {
        // onDone = event handler to run on successful download
        // onProgress = event handler to run during a download
        // url = url to load
        // data = extra parameters to be sent with the AJAX request
        var content_length = null;
    
        self.meta_xhr = $.ajax({
            url: url,
            data: data,
            dataType: 'json',
            type: 'HEAD',
            success: function(data, status, jqXHR)
            {
                content_length = jqXHR.getResponseHeader("X-Content-Length");
            }
        });
    
        self.xhr = $.ajax({
            url: url,
            data: data,
            success: onDone,
            dataType: 'json',
            progress: function(jqXHR, evt)
            {
                var pct = 0;
                if (evt.lengthComputable)
                {
                    pct = 100 * evt.position / evt.total;
                }
                else if (self.content_length != null)
                {
                    pct = 100 * evt.position / self.content_length;
                }
    
                onProgress(pct);
            }
        });
    }
    

    And then to use it:

    loader(function(response)
    {
        console.log("Content loaded! do stuff now.");
    },
    function(pct)
    {
        console.log("The content is " + pct + "% loaded.");
    },
    '', {});
    

    On the server side, set the X-Content-Length header on both the GET and the HEAD requests (which should represent the uncompressed content length), and abort sending the content on the HEAD request.

    In PHP, setting the header looks like:

    header("X-Content-Length: ".strlen($payload));
    

    And then abort sending the content if it's a HEAD request:

    if ($_SERVER['REQUEST_METHOD'] == "HEAD")
    {
        exit;
    }
    

    Here's what it looks like in action:

    screenshot

    The reason the HEAD takes so long in the below screenshot is because the server still has to parse the file to know how long it is, but that's something I can definitely improve on, and it's definitely an improvement from where it was.

提交回复
热议问题