首页 > 解决方案 > 如何从 ajax 加载的数据中下载 pdf 文件或获取通过 axios 调用我们 Api 的调用快速路由?

问题描述

我尝试下载我们的 API 生成的 pdf 文件。

流程:单击“下载”按钮触发获取快速路线的功能。路由通过 axios 调用我们的 API。API 生成一个 pdf 并返回一个原始数据 pdf 文件(字符串)。路由得到axios的响应。为了将此响应发送回 fetch,我将响应放入对象 {pdf: response} 并使用 res.json({pdf: response}) 将其发送回。在 fetch.then() 中,我需要将响应转换为 blob 并在其上使用 URL.createObjectURL 创建一个不可见的下载链接以触发点击它并开始下载。

问题: res.json({pdf: response}) 发送的响应无法转换为blob,因为它不是pdf数据,它是一个包含pdf数据的json。

按钮点击触发的动作:

var url = "/routePath";

fetch(url)
    .then(response => response.blob())
    .then(blob => {
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.style.display = 'none';
        a.href = url;
        // the filename you want
        a.download = couponName + '.pdf';
        document.body.appendChild(a);
        a.click();
        window.URL.revokeObjectURL(url);
    })
    .catch((error) => console.error(error));

服务器端的快速路由处理:

router.get('/routePath', async function(req, res, next) {

    const pdf = await Api.send(req, 'entity', 'action', {data}, {});
    res.json({pdf: pdf});
});

通过 Axios 调用:

const config = require(`../config/config.${process.env.NODE_ENV}.json`);
const axios = require('axios');

module.exports = {
    send: async function(req, entity, action, data, pathValues){
        let response = false;

        try {
            // Prepare headers
            let headers = {'Content-Type': 'application/json'};
            
            // Request
            let axiosConfig = {
                method: 'get',
                headers,
                url: path,
                data: data,
                validateStatus: false
            };
            axiosConfig.params = data;

            response = await axios(axiosConfig);

            if (response.data == '') response.data = {};
            response = response.data;
            response.callSuccess = true;
        } catch(error) {
            console.error(error);
            if (error.response){

                response = error.response.data;
                response.callSuccess = false;
                console.error(response);
            }
            else {
                console.error(error);
            }
            
        }

        return response;
    }

}

标签: jquerynode.jsexpressaxiosfetch

解决方案


客户端:

我为 Ajax 切换了 Fetch 以获得更多的兼容性(即)。我还使用 base64ToArrayBuffer 进行转换,接收到的 pdf 数据能够将其转换为 blob。

[...]
var url = "/routePath";

    $.ajax({ url: url })
    .done(function(pdf) {
        const arraybuffer = base64ToArrayBuffer(pdf);
        const blob = new Blob([arraybuffer], {type: 'application/pdf'});
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.style.display = 'none';
        a.href = url;
        a.download = 'GoCoupons.' + couponName + '.pdf';
        document.body.appendChild(a);
        a.click();
        window.URL.revokeObjectURL(url);
    })
    .fail(function(error) {
        console.error(error);
    })

    [...]

function base64ToArrayBuffer(data) {
    var binaryString = window.atob(data);
    var binaryLen = binaryString.length;
    var bytes = new Uint8Array(binaryLen);
    for (var i = 0; i < binaryLen; i++) {
        var ascii = binaryString.charCodeAt(i);
        bytes[i] = ascii;
    }
    return bytes;
}

服务器端:

我没有返回 json,而是从我们的 API 发送 pdf 响应。

router.get('/routePath', async function(req, res, next) {
    const pdf = await Api.send(req, 'entity', 'action', {data}, {});
    res.send(pdf);
});

axios调用还是一样

const config = require(`../config/config.${process.env.NODE_ENV}.json`);
const axios = require('axios');

module.exports = {
    send: async function(req, entity, action, data, pathValues){
        let response = false;

        try {
            // Prepare headers
            let headers = {'Content-Type': 'application/json'};
            
            // Request
            let axiosConfig = {
                method: 'get',
                headers,
                url: path,
                data: data,
                validateStatus: false
            };
            axiosConfig.params = data;

            response = await axios(axiosConfig);

            if (response.data == '') response.data = {};
            response = response.data;
            response.callSuccess = true;
        } catch(error) {
            console.error(error);
            if (error.response){

                response = error.response.data;
                response.callSuccess = false;
                console.error(response);
            }
            else {
                console.error(error);
            }
            
        }

        return response;
    }

}

推荐阅读