React/Redux下载文件 [英] React/Redux download file

查看:231
本文介绍了React/Redux下载文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

单击按钮后,我需要从服务器下载文件.

我创建了MaterialUI按钮,并在其onclick回调上调用了容器组件已连接的操作.

该操作是异步的,并且执行ajax POST:

export const onXlsxClick = () => dispatch => {
    const urlParams = {
        filters: {
            aggregation: 'macro_area',
            chart_resolution: '1_hour',
            chart_from: '1478080363',
            chart_to: '1477993963'
        },
        labels: ['PROVA1', 'PROVA2'],
        series: [
            {
                label: null,
                timestamp: 1478080363,
                values: [123, 345]
            },
            {
                label: null,
                timestamp: 1477993963,
                values: [153, 3435] 
            }
        ]
    };
    return $.ajax({
        url:'/rest/export/chart/xlsx',
        type: 'POST',
        dataType: 'application/json',
        contentType: 'application/json',
        data: JSON.stringify(urlParams)
    })
    .done(data => {
       console.log('success');
    })
    .fail(error => {
        console.log(error);
    });
};

服务器接收请求并通过此REST服务正确处理它:

@POST
@Path("xlsx")
@Produces("application/vnd.ms-excel")
public Response getXlsx(ChartExportRequest request) {
    ResponseBuilder responseBuilder;
    ChartExportRequestDTO reqDto = null;
    try {
        reqDto = parseDTO(request);
        checkRequestDTO(reqDto);
        ExportDTO dto = getXlsxProvider().create(reqDto);

        responseBuilder = Response.ok(dto.getFile())
                .header("Content-disposition", "attachment;filename=" + dto.getFileName());
    }
    catch(Exception e) {
        logger.error("Error providing export xlsx for tab RIGEDI with request [" + (reqDto != null ? reqDto.toString() : null) + "]", e);
        responseBuilder = Response.serverError().entity(e.getMessage());
    }
    return responseBuilder.build();
}

问题是响应正确到达客户端,但是什么也没发生:我希望浏览器显示下载对话框(例如:在chrome浏览器中,我希望下载的底部栏与我的文件一起出现.)

我在做什么错了?

解决方案

根据Nate的回答此处,Ajax请求的响应浏览器无法将其识别为文件.对于所有Ajax响应,它的行为都相同. 您需要手动触发下载弹出窗口.

在我的实现中,一旦收到,我就使用 filesaverjs 触发下载弹出窗口reducer中的API响应.

由于FileSaver使用blob保存文件,因此我将来自服务器的响应作为blob发送,将其转换为字符串数组缓冲区,然后使用它来保存我的文件.

中介绍了这种方法

请在下面找到该减速器的示例代码: (根据Redux使用reducer进行状态修改) reducer.js

 let fileSaver = require("file-saver");


export default function projectReducer(state = {}, action)
{
    let project;
    switch (action.type) {
        case  GET_PROJECT_SUCCESS :
            project = Object.assign(action.response.data);
            return project;
        case EXPORT_AND_DOWNLOAD_DATA_SUCCESS :
            let data = s2ab(action.response.data);
            fileSaver.saveAs(new Blob([data], {type: "application/octet-stream"}), "test.xlsx");
            return state;


    }
    return state;

}

function s2ab(s) {
    var buf = new ArrayBuffer(s.length);
    var view = new Uint8Array(buf);
    for (var i = 0; i != s.length; ++i) {
        view[i] = s.charCodeAt(i) & 0xFF;
    }
    return buf;
} 

I need to download a file from the server when a button is clicked.

I created a MaterialUI button and on its onclick callback i call an action of the container component connected.

The action is asynchronous and does an ajax POST:

export const onXlsxClick = () => dispatch => {
    const urlParams = {
        filters: {
            aggregation: 'macro_area',
            chart_resolution: '1_hour',
            chart_from: '1478080363',
            chart_to: '1477993963'
        },
        labels: ['PROVA1', 'PROVA2'],
        series: [
            {
                label: null,
                timestamp: 1478080363,
                values: [123, 345]
            },
            {
                label: null,
                timestamp: 1477993963,
                values: [153, 3435] 
            }
        ]
    };
    return $.ajax({
        url:'/rest/export/chart/xlsx',
        type: 'POST',
        dataType: 'application/json',
        contentType: 'application/json',
        data: JSON.stringify(urlParams)
    })
    .done(data => {
       console.log('success');
    })
    .fail(error => {
        console.log(error);
    });
};

The server receive the request and handle it correctly through this REST service:

@POST
@Path("xlsx")
@Produces("application/vnd.ms-excel")
public Response getXlsx(ChartExportRequest request) {
    ResponseBuilder responseBuilder;
    ChartExportRequestDTO reqDto = null;
    try {
        reqDto = parseDTO(request);
        checkRequestDTO(reqDto);
        ExportDTO dto = getXlsxProvider().create(reqDto);

        responseBuilder = Response.ok(dto.getFile())
                .header("Content-disposition", "attachment;filename=" + dto.getFileName());
    }
    catch(Exception e) {
        logger.error("Error providing export xlsx for tab RIGEDI with request [" + (reqDto != null ? reqDto.toString() : null) + "]", e);
        responseBuilder = Response.serverError().entity(e.getMessage());
    }
    return responseBuilder.build();
}

The problem is that the response arrives correctly to the client but then nothing happens: I am expecting that the browser shows the download dialog (example: in chrome I expect the bottom bar of downloads to appear with my file).

What am I doing wrong?

解决方案

AS per Nate's answer here, the response of Ajax request is not recognised by a browser as a file. It will behave in the same way for all Ajax responses. You need to trigger the download popup manually.

In my implementation, I used filesaverjs to trigger the download popup, once I have received the API response in reducer.

Since FileSaver uses blob for saving the file, I am sending the response from server as a blob, converting it into string array buffer and then using it to save my file. This approach was described in

Please find the sample code below for the reducer : (using reducer for state modification, as per Redux) reducer.js

let fileSaver = require("file-saver");


export default function projectReducer(state = {}, action)
{
    let project;
    switch (action.type) {
        case  GET_PROJECT_SUCCESS :
            project = Object.assign(action.response.data);
            return project;
        case EXPORT_AND_DOWNLOAD_DATA_SUCCESS :
            let data = s2ab(action.response.data);
            fileSaver.saveAs(new Blob([data], {type: "application/octet-stream"}), "test.xlsx");
            return state;


    }
    return state;

}

function s2ab(s) {
    var buf = new ArrayBuffer(s.length);
    var view = new Uint8Array(buf);
    for (var i = 0; i != s.length; ++i) {
        view[i] = s.charCodeAt(i) & 0xFF;
    }
    return buf;
}

这篇关于React/Redux下载文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆