How to set xhr request headers with kendo.saveAs()?

4 posts, 1 answers
  1. Insad
    Insad avatar
    28 posts
    Member since:
    Jan 2010

    Posted 01 Feb Link to this post

    Hello Telerik,

     

    I have a problem with the kendo.saveAs() because the server, where the binary files come from, requires an 'Authorization' in the request headers.

    I have been looking for an answer but all I found was that the question was asked before, by somebody else, on StackOverflow: http://stackoverflow.com/questions/41406918/kendo-server-export-post-request-headers

    But no useful answer was given so i pop the question here because I do need an answer for this :(

     

    Best regards,

     

    Insad

  2. Boyan Dimitrov
    Admin
    Boyan Dimitrov avatar
    1873 posts

    Posted 03 Feb Link to this post

    Hello,

    Internally the kendo.saveAs methods creates a forma and sends it to the server. I am afraid that it is not really a XMLHttpRequest and so xhr request header is not possible to be set. 

    Regards,
    Boyan Dimitrov
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  3. Insad
    Insad avatar
    28 posts
    Member since:
    Jan 2010

    Posted 09 Feb in reply to Boyan Dimitrov Link to this post

    Hello Boyan,

    I build a solution for this based on some info found elsewhere on the internet.

    I would like to share it with you, so perhaps Telerik might want to use is in some future version ;)

     

    //#region -- Download file and save data to a local file --
        // Invoke call to webservice and save file
        // url - Url to get the file from
        // method - GET/POST method
        // defaultFilename - Default filename if none was given from the server
        , saveAs: function (url, method, defaultFilename)
        {
            var caller = this;
     
            Insad.ajaxMaskUI({
                url: url,
                type: method,
                headers: {
                    'Authorization': Insad.GetBaseAuthenticationToken()
                    // ... Put your headers in here ...
                },
                maskUI: Insad.defaultMaskUI
                , maskPageMsg: 'Downloading file'
            })
            .fail(function (xhr, textStatus, errorThrown) {
                //console.log('error:', textStatus, errorThrown, xhr.getAllResponseHeaders(), xhr);
                var msg = xhr.responseText;
                if (msg === undefined) {
                    msg = 'Unknown error';
                }
                console.log('FileDownload failed -> Error handler. Errormessage: ', msg);
                ShowWarning(msg);
     
                caller.handleUIErrorDownload();
            })
            .done(function (data, textStatus, xhr) {
                caller.handleUISuccessDownload(xhr, defaultFilename);
            });
        }
        , handleUIErrorDownload: function ()
        {
            console.log('handleUIError');
            // TODO: Reset stuff / give user more info?
            // ... Put your code in here ...
        }
        , handleUISuccessDownload: function (xhr, defaultFilename)
        {
            console.log('handleUISuccess');
     
            // Save file
            var filename = Insad.GetFilenameFromContent(xhr);
            if (filename === '') {
                filename = defaultFilename;
            }
            Insad.SaveDataToFile(filename, xhr.responseText, xhr.getResponseHeader('Content-Type'));
     
            // TODO: Give user more info?
            // ... Put your code in here ...
        }
    //#endregion
     
    //#region -- Save data to a local file --
        // Get the filename from the Content-Disposition in the response xhr
        , GetFilenameFromContent: function (xhr)
        {
            var filename = '';
            var disposition = xhr.getResponseHeader('Content-Disposition');
            // Only when inline or attachment are supported at this moment
            if (disposition && (disposition.indexOf('attachment') !== -1 || disposition.indexOf('inline') !== -1)) {
                var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
                var matches = filenameRegex.exec(disposition);
                if (matches != null && matches[1]) {
                    filename = matches[1].replace(/['"]/g, '');
                }
            }
            return filename;
        }
     
        // The function that will write the data to a file :)
        , SaveDataToFile: function (filename, data, mimeType)
        {
            var dataFileAsBlob = new Blob([data], {type:mimeType});
            var downloadLink = document.createElement("a");
            downloadLink.download = filename;
            downloadLink.innerHTML = "Download";
            if (window.webkitURL !== null) {                        // Is it Chrome based?
                // Chrome allows the link to be clicked
                // without actually adding it to the DOM.
                downloadLink.href = window.webkitURL.createObjectURL(dataFileAsBlob);
            }
            else {
                // Firefox requires the link to be added to the DOM
                // before it can be clicked.
                downloadLink.href = window.URL.createObjectURL(dataFileAsBlob);
                downloadLink.onclick = destroyClickedElement;       // --> TODO: ?? TEST ?? On Opera use: downloadLink.onclick = document.body.removeChild(event.target);
                downloadLink.style.display = "none";
                document.body.appendChild(downloadLink);
            }
            // Force download
            downloadLink.click();
        }
    //#endregion

    This is a part from our base library (Insad).

    I think you get the idea. If you're missing something I would be happy to provide it to you :)

    Instead of calling the 'old' saveAs like:

    kendo.saveAs({
        dataURI: url,
        fileName: defaultFilename,
        forceProxy: false
    });


    You can now use:

    Insad.saveAs({
        dataURI: url,
        method: 'GET'// or use 'POST' if you really must ;)
        fileName: defaultFilename
    });

    I left out the animation part but that shouldn't be to hard I think :)

    Best regards,

    Albert van Peppen (Insad)

  4. Answer
    Boyan Dimitrov
    Admin
    Boyan Dimitrov avatar
    1873 posts

    Posted 10 Feb Link to this post

    Hello,

    Thank you for sharing this solution with our community. I am sure that someone will find it useful. 

    Regards,
    Boyan Dimitrov
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
Back to Top