What causes AJAX to sometimes output with incorrect encoding?

After receiving a file from a server using AJAX (Angular), the file, a simple XLSX document, is sent as shown below:

ob_start();
$file = \PHPExcel_IOFactory::createWriter($xls, 'Excel2007');
$file->save('php://output');
$response->setContent(ob_get_clean());
$response->headers->replace(array(
    'Content-Type'          => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
    'Content-Disposition'   => 'attachment;filename=file.xlsx"'
));

When making a request from the frontend, the Accept header is used. The file is saved using angular-file-saver with FileSaver.js and Blob.js. However, the received file is corrupt and cannot be opened in Excel; its size is (for example) 12446 bytes, while Chrome's DevTools Network tab displays a Content-Length header of 7141 bytes.

How can this issue be resolved?

UPD: The request is sent in the following manner:

$http.get(baseURL + '/' + entity + '/export/?' + condition + sort, {
          headers: {'Accept': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=utf-8'}
        });

The file is downloaded as follows:

var data = new Blob([response.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8'});
          FileSaver.saveAs(data, 'file.xlsx');

Answer №1

To overcome the issue, I decided to use plain JavaScript AJAX instead of AngularJS. It seems there may be a problem with AngularJS and JQuery when handling binary responses.

Here is an alternative solution that should work:

var request = new XMLHttpRequest();
request.open('GET', 'http://yourserver/yourpath', true);
request.responseType = 'blob';

request.onload = function (e) {
    if (this.status === 200) {
        var blob = this.response;
        if (window.navigator.msSaveOrOpenBlob) {
            var fileNamePattern = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
            window.navigator.msSaveBlob(blob, fileNamePattern.exec(request.getResponseHeader("content-disposition"))[1]);
        } else {
            var downloadLink = window.document.createElement('a');
            var contentTypeHeader = request.getResponseHeader("Content-Type");
            var b = new Blob([blob], { type: contentTypeHeader });
            downloadLink.href = window.URL.createObjectURL(b);
            var fileNamePattern = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
            downloadLink.download = fileNamePattern.exec(request.getResponseHeader("content-disposition"))[1];
            document.body.appendChild(downloadLink);
            downloadLink.click();
            document.body.removeChild(downloadLink);
            window.URL.revokeObjectURL(b);
        }
    }
};
request.send();

This code snippet is inspired by this and this.

On a side note, I discovered that using new Blob([response.data], ...) results in almost double the size of response.data when response.data is not returned as a blob, but as text/plain or

application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
. To address this, you should pass it an array of bytes instead:

    var i, l, d, array;
    d = this.result;
    l = d.length;
    array = new Uint8Array(l);
    for (var i = 0; i < l; i++){
        array[i] = d.charCodeAt(i);
    }
    var b = new Blob([array], {type: 'application/octet-stream'});
    window.location.href = URL.createObjectURL(b);

This code reference can be found here.

Given that the AJAX response may not be correct when using AngularJS, following this method will not provide a valid xlsx file. It's recommended to stick with vanilla JavaScript in this scenario.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I can't seem to get anything to show up on my React

After starting to work with routing on react.JS, I encountered a challenge where the simple products.jsx file is supposed to display a simple message upon clicking, but it's not showing anything. Here is the code from Index.JS import React from &apos ...

Utilize Web3.js to interact with a specific function in a deployed smart contract on the Ethereum blockchain from a React application

I am attempting to execute the transferMargin() function from the Synthetix Contract on Optimism Kovan using react/javascript (web3.js) and Metamask. I am encountering an issue where I am unable to successfully trigger the transferMargin function upon a Bu ...

The process of implementing web-based online diagramming software involves a strategic approach to designing and integrating various

I'm really interested in learning how web-based online diagramming software works. If anyone could provide guidance or point me to example resources, I would greatly appreciate it. Here are some of the web-based online tools that I have been explorin ...

AJAX is not meeting my expectations

Is there an issue with this code? It's supposed to insert data into the database but I'm not getting any errors. I am new to using ajax, and I found this code which I modified slightly. I thought it would work, but it's not functioning as e ...

Verifying Initialization Before Destructing jQuery File Upload

I'm currently working with the blueimps jQuery file upload plugin and I need to delete all existing instances before creating new ones. The issue I'm running into is that I receive an error when attempting something like this: $('.upload&ap ...

Using more than one class at a time is causing issues

Essentially, I have a div and I want to create an exercise where I apply three different classes using vue.js. I attempted to use v-bind:class, specifically :class, but can I bind a class directly from CSS? This is what I tried: html <div :style="[my ...

Error: An issue occurred with the tasks in the Gruntfile.js file

pm WARN EPACKAGEJSON <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="74041506001a1106041b0600151834445a445a44">[email protected]</a> No description npm WARN EPACKAGEJSON <a href="/cdn-cgi/l/email-protection" ...

Experiencing a lack of defined or no outcome when outputting the API callback

I am troubleshooting an issue with my script that searches for movie titles from a database. While I receive results in the console without any errors, the renderMovies function is not storing the API movie title, plot, and other details properly in my var ...

What steps do I need to take in order to include REMOVE and EDIT buttons in my table?

In the index.html file, there is a teacher table that is only displayed after clicking on the button Teachers: <div class="container"> <table class="teacherTable" border="1" width="100%" cellpadding=&qu ...

The v-for directive is displaying my list in a single row with multiple columns instead of in a single column with multiple rows

Can someone please assist in rendering my list as shown below: A B C The current rendering looks like this: 1: A 2: B 3: C Below is the code snippet: To-Do List: <input type="text" class = "todo" placeholder = "Next Item" v-on:keyup.enter="add ...

Adjust the language code in a URL using JavaScript or Node.js

Within my common header file, there is a navbar that includes a multilanguage dropdown menu. The issue I am facing is that when I select a language from the dropdown, the page translates correctly. However, when I navigate to other pages, the selected lang ...

Ways to ensure the text on my website scrolls into view as the user navig

Is there a way to have my text show up as I scroll? I came across this , but I'm interested in how it actually functions. I saw a similar inquiry before, but it doesn't make sense to me. Can someone please explain or provide some examples on how ...

What is causing the initial activation of the <button> within a form?

Within my <form>, I have included 2 submit buttons. The first button looks like this: <button class="regular" id="geocodesubmit" style="height:40px;">Set Location</button> The second button looks like this: <button type="submit" ...

The ng-controller directive is not functioning accurately

I attempted to execute the following basic HTML: <!DOCTYPE html> <html ng-app="tempApp"> <head> <script src="js_libs/angular/angular.min.js"></script> <script src="js_libs/angular/bootstrap.js"></script&g ...

I'm only seeing output on two of my input boxes - what's going on?

Currently in the process of learning JQUERY/HTML, I decided to create a shopping cart. My goal is to display the subtotal, tax, shipping costs, and total cost in input boxes. While I successfully displayed the sub total and shipping cost, I encountered an ...

What is the method for including an input field beside the y-axis label in Chart.js?

I'm struggling to implement a live poll using Chart.js where users can select their option by checking a checkbox next to the y-axis label. My initial attempt was unsuccessful as placing the input boxes outside of the canvas led to alignment issues wi ...

Can Cell be rendered into a targeted element?

Can a Cell from CellJS be rendered into a specific HTML element? For example, including a Cell alongside some static HTML that is not managed by cell. Or having two separate Cell apps on a single page. <!DOCTYPE html> <html> <header> ...

How to globally register components in Vuejs located in subdirectories

I've been working through the documentation on the Vuejs website to understand how to globally register vue components. In my setup, I've specified that the components folder's relative path is ./global and I've set it to look into sub ...

What methods can be used to search within one array in order to filter another array contained in a list?

Looking for suggestions on creating a filter in one list based on another list How can I handle filtering an array within a list by searching in another array? For example... myArray = [ { "name": "Item-A", "tags": ["Facebook" ...

Using Jquery to locate the next div element

I've created this code snippet, but it's not functioning as expected. However, by reviewing it, you can understand my intended outcome: $('.jfmfs-alpha-separator').filter(function() { return ($(this).next().not(".hide-filtered"). ...