Retrieve a PDF file from an HTTP response using Axios

I'm currently working on a project that involves integrating Vue with a Laravel API as the back-end. One of the requirements is to be able to download PDF files from the server when a certain link is clicked. I am using axios for making GET requests, which successfully retrieves the PDF file in the response body. However, I need a way to directly download this file without any additional user interaction.

To provide a clearer understanding of the response structure, here's a visual representation: https://i.sstatic.net/Z5ozo.png (Disclaimer: A text-based example would be more practical but due to the PDF content length, it's not feasible)

Is there a method or workaround in JavaScript to achieve a direct file download without requiring the user to click on another button?

Code

// This function is triggered upon clicking a specific link
downloadFile(id) {
    const specificationId = this.$route.params.specificationId;

    axios
        .get(`${this.$API_URL}/api/v1/suppliersmanagement/product-specifications/${specificationId}/fileupload/${id}/download`, {
            headers: this.headers,
        })
        .then(response => {
            console.log(response);
            // Implement direct file download logic here..
        })
        .catch(error => console.log(error));
},

Answer №1

Following the recommendation from @Sandip Nirmal, I decided to utilize the downloadjs library and found it to be quite effective! I did have to tweak some parts of my code, but in the end, everything worked smoothly.

Here is my updated code:

// npm i downloadjs
import download from 'downloadjs'

// method
downloadFile(file) {
    const specificationId = this.$route.params.specificationId;

    axios
        .get(`${this.$API_URL}/api/v1/suppliersmanagement/product-specifications/${specificationId}/fileupload/${file.id}/download`, {
            headers: this.headers,
            responseType: 'blob', // had to add this one here
        })
        .then(response => {
           const content = response.headers['content-type'];
           download(response.data, file.file_name, content)
        })
        .catch(error => console.log(error));
},

Answer №2

To handle binary data in your axios request, utilize the 'responseType' option like this:

axios.get(
  url, 
  {responseType: 'blob'} // This is important!
).then((response) => {
  window.open(URL.createObjectURL(response.data));
})

Answer №3

There are two ways to go about this task. If you're working with a Node.js backend, you can easily accomplish it using the res.download method of express. Check out this answer for more details: Download a file from NodeJS Server using Express.

However, if you prefer handling it from the client side, there are limited options since direct file downloads using axios, XHR, or fetch is not possible. You can utilize download.js or write your own code as shown below.

return axios({
    url: '/download', // download url
    method: 'get',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
      mode: 'no-cors'
    }
  })
    .then(response => response.blob())
    .then(blob => {
      var url = window.URL.createObjectURL(blob)
      var a = document.createElement('a')
      a.href = url
      a.download = fileName
      a.click()
      a.remove()
      setTimeout(() => window.URL.revokeObjectURL(url), 100)
    })

Since the server response is in json format, you'll need to convert it into an ObjectURL and assign it to the anchor tag.

If you explore the code within download.js, you'll notice a similar implementation.

Answer №4

Discover a new approach for 2022: leveraging node.js, fs.promises, and the power of async/await

Incorporate the use of responseType: 'stream' as recommended in the Axios documentation.

import axios from 'axios';
import { writeFile } from 'fs/promises';

const downloadFile = async () => {
  const response = await axios.get('https://someurl', {
    params: {
      // ...
    },
    // Make sure to set responseType to 'stream' as outlined in the docs
    responseType: 'stream',
  });
  const pdfContents = response.data;
  await writeFile('file.pdf', pdfContents);
};

Answer №5

function generatePDFLink(id, name) {
    fetchPdf(`https://api.example.com/pdf/invoice/${id}`, name);
}

const fetchPdf = async (url, fileName) => {
    try {
        const response = await fetch(url, {
            method: 'GET',
            headers: {
                'Authorization': 'Bearer ' + localStorage.getItem('token'),
                'Content-Type': 'application/json'
            }
        });
        
        if (!response.ok) {
            throw new Error('Failed to download PDF');
        }

        const blob = await response.blob();
        const urlObject = URL.createObjectURL(blob);

        const a = document.createElement('a');
        a.href = urlObject;
        a.download = `${fileName}.pdf`;
        document.body.appendChild(a);
        a.click();
        a.remove();
    } catch (error) {
        console.error(error);
    }
}

Answer №6

Follow this method to achieve the desired outcome

saveFileToDownload(fileName) {
  fetch(url , { headers })
  .then(response => response.blob())
  .then(blobData => URL.createObjectURL(blobData))
  .then(fileUrl => {
    var newLink = document.createElement("a");
    newLink.href = fileUrl;
    newLink.download = fileName + ".csv";
    document.body.appendChild(newLink);
    newLink.click();
    document.body.removeChild(newLink);
  });
}

In this code snippet, I am demonstrating how to download a CSV file by appending .csv extension to the filename.

Answer №7

I faced a similar issue, but I managed to resolve it successfully.

Here's how I downloaded the PDF using NodeJs and Axios:

 const url = `https://www.buds.com.ua/images/Lorem_ipsum.pdf`;
 return await axios.get(url, { responseType: 'stream' });

If you need to pass on the .pdf content through your own API, you'll need to send it as a data stream. Here's how you can implement this:

response.data.pipe(res);

Therefore, the complete code for your API would look like this:

async function forwardPDF(req, res) {
  try {
    // Fetch the PDF from the URL
    const url = `https://www.buds.com.ua/images/Lorem_ipsum.pdf`;
    const response = await axios.get(url, { responseType: 'stream' });

    // Pipe the PDF to the response
    response.data.pipe(res);

  } catch (error) {
    const header = Header(true, error.statusCode, error.message, error.stack);
    res.send(Response(header, {}));
  }
}

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

Optimizing Three.js for better performance

Recently, I delved into working with three.js and webgl for a personal project. My goal was to develop a wardrobe model based on user input. You can check out the project at this link: Initially, the rendering speed was fast and smooth without Materials a ...

Prevent ui-select from being highlighted when clicked

here's a dilemma : (all in angular 1) I'm using a ui-select like this : https://i.stack.imgur.com/RzH2u.png Here's the code snippet : <div class="formZone-group"> <div class="mandatory-fl"> <div class="man ...

Executing JavaScript code externally on Electron's local server

During local development, I prefer to store all of my separate JS scripts in a different folder. However, the only way I have found to do this is by omitting the declaration of the meta statement. Unfortunately, this omission triggers a warning message. ...

react component fails to rerender upon state change

I am struggling with a React functional component that includes a file input. Despite selecting a file, the text in the h1 tag does not change from choose file to test. The handleChange function is triggered successfully. A console.log statement confirm ...

Why is the decision made to simply remove an item? Is there an option to instead choose and delete the specific item?

I am facing an issue with my form where I have a function to dynamically add inputs using "append" and another button to remove the inputs added. When I use the "last-child" selector to delete the last generated div, the remove button stops working and I a ...

Tips for preventing focus/autofocus on the initial form input using bootstrap/jquery

I am currently working on updating an application that utilizes jQuery 3.4 and Bootstrap 3.4. A form has been added to the bottom of the page, but it has an unintended consequence of the browser focusing on the first input element (checkbox) within that fo ...

After an ajax request, the Jquery hover effects are no longer functional

On my website, I have implemented ajax calls to filter product results and apply effects. However, the effects on these products seem to stop working after the ajax call is completed. Located at the bottom of the page's code is the following script: ...

Transform TypeScript class into an object

Is there a way to transfer all values from one typescript class, Class A, to another matching class, Class B? Could there be a method to extract all properties of Class A as an object? ...

What is the best way to center align an element while having another element situated directly below it?

I want to create a grid of "clock" elements, with five clocks in each row. Below each clock, I'd like to display the DAY and DATE centered with the clock (day on top line, date below). Since I'm new to html/css, I appreciate your patience. Here&a ...

How can you utilize a previously opened window from another page in JavaScript?

One of my challenges involves managing windows in a JavaScript environment. When I open a child window using window.open("http://foobar","name"), it reuses the same window when opened with the same name, which is exactly what I want. However, if the origi ...

Tips for implementing ajax and codeigniter to load additional comments on a web page

Is it possible to customize Codeigniter's default pagination to achieve a "viewMore" link style when loading more records using AJAX? The challenge lies in creating a div that automatically expands to handle large numbers of records, such as 10,000 a ...

Is Your Website Sluggish because of an Excessive Amount of JavaScript on Page

After finally resolving some of the Javascript issues I was facing, I have streamlined my code to utilize just one library now, which is a huge improvement from how chaotic it was before. However, I have noticed a slight delay in the page load time, and I ...

Using jQuery to select and animate several elements simultaneously without repeating the animation

Issue Summary (Fiddle): I'm trying to make all elements fade out simultaneously when clicked, but the current code causes the target to trigger three times resulting in three alert() calls. I want them to fade together without using a wrapper element ...

Present Different Content for Visitors Using Ad-Blocking Software

I am currently working on a project that is supported by ads. These ads are subtle and relevant to the content, not obnoxious popups for questionable products. However, since the project relies on ad revenue, users with Ad Blockers unfortunately do not co ...

What is the process for adding a highlighted area beneath a curve on a high chart?

I am working on creating a high chart with Angular 4 and I have a specific requirement to highlight certain portions of the Highchart. For example, in the image: In the image above, if a data point value drops below a certain limit (such as 0), it shoul ...

Jquery display function experiencing unresponsiveness

Currently, I am trying to implement some show/hide functionality in my JavaScript file: $(document).ready(function() { $('#me').hide(); $('#send').click(function() { $('#me').show("slow"); }); }); Strange ...

Potential causes for Chrome to send duplicate requests

In my nginx server logs, I have the following entries (IPs and paths altered for illustration purposes): 101.101.101.101 - - [15/Apr/2020:14:46:03 +0000] "GET /item/download-file/ready/5e971e290107e HTTP/2.0" 200 142940 "https://example.com/referer" "Mo ...

Why do we need to use [`expression`] notation?

I've recently started exploring reactjs and I came across this code snippet: handleChange = event => { const { name, value } = event.target this.setState({ [name]: value, }) } I'm a bit puzzled about the notation used here: [name ...

Issue Arising During File Transfer in Nativescript

I am currently attempting to upload an image that I captured with Nativescript to a server using a web API that I created in C# (ASP.NET). The API works perfectly fine when tested on Postman, but I encounter an error "Error During Upload" while trying to u ...

A guide to handling JSON parsing in JavaScript when the value contains nested JSON data

I am struggling with parsing this JSON object: { "key1" : "value", "key2" : "{ "innerkey1": "value", "innerkey2": "value"}" } Here is an example of how I am trying to parse it: var myData = JSON.parse(data); $(document).ready(function() { var ...