当前位置: 首页 > 知识库问答 >
问题:

如何下载react as文件中的fetch响应

顾亦
2023-03-14
export function exportRecordToExcel(record) {
    return ({fetch}) => ({
        type: EXPORT_RECORD_TO_EXCEL,
        payload: {
            promise: fetch('/records/export', {
                credentials: 'same-origin',
                method: 'post',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify(data)
            }).then(function(response) {
                return response;
            })
        }
    });
}

返回的响应是.xlsx文件。我希望用户能够将其保存为一个文件,但什么也没有发生。我假设服务器正在返回正确类型的响应,因为在控制台中它说

Content-Disposition:attachment; filename="report.xlsx"

我错过了什么?我在减速机里该怎么办?

共有1个答案

令狐高洁
2023-03-14

浏览器技术目前不支持直接从Ajax请求下载文件。相关的工作是添加一个隐藏的表单,并在后台提交它,以使浏览器触发保存对话框。

我正在运行一个标准的流量实现,所以我不确定确切的Redux(Reducer)代码应该是什么,但我刚刚为文件下载创建的工作流是这样的...

  1. 我有一个名为FileDownLoad的React组件。这个组件所做的就是呈现一个隐藏的表单,然后在componentdidmount内立即提交表单并调用它的ondownloadcompleteprop.
  2. 我还有另一个React组件,我们称之为widget,它有一个下载按钮/图标(实际上有很多个...表中的每个项都有一个)。小部件具有相应的操作和存储文件。小部件导入filedownload.
  3. 小部件有两个与下载相关的方法:handledownloadhandledownloadcomplete.
  4. Widgetstore有一个名为DownloadPath的属性。默认设置为null。当它的值设置为null时,没有文件下载正在进行,并且widget组件不呈现filedownload组件。
  5. 单击小部件中的按钮/图标调用HandleDownload方法,该方法触发DownloadFile操作。DownloadFile操作不发出Ajax请求。它将download_file事件分派到存储区,同时发送要下载的文件的downloadpath。存储区保存downloadpath并发出更改事件。
  6. 因为现在有了downloadpath小部件将呈现filedownload,传入必要的道具,包括downloadpath以及handledownloadcomplete方法,作为ondownloadcomplete的值。
  7. 当呈现filedownload并使用method=“get”(POST也应该起作用)和action={downloadPath}提交表单时,服务器响应将触发浏览器的目标下载文件保存对话框(在IE9/10、最新的Firefox和Chrome中测试)。
  8. 紧随表单submit之后,将调用ondownloadcomplete/handledownloadcomplete。这将触发另一个派发download_file事件的操作。但是,这次DownloadPath被设置为null。存储区将downloadpath保存为null并发出更改事件。
  9. 因为不再有downloadpathfiledownload组件不在小部件中呈现,所以这个世界是一个快乐的地方。

widget.js-仅部分代码

import FileDownload from './FileDownload';

export default class Widget extends Component {
    constructor(props) {
        super(props);
        this.state = widgetStore.getState().toJS();
    }

    handleDownload(data) {
        widgetActions.downloadFile(data);
    }

    handleDownloadComplete() {
        widgetActions.downloadFile();
    }

    render() {
        const downloadPath = this.state.downloadPath;

        return (

            // button/icon with click bound to this.handleDownload goes here

            {downloadPath &&
                <FileDownload
                    actionPath={downloadPath}
                    onDownloadComplete={this.handleDownloadComplete}
                />
            }
        );
    }

widgetActions.js-仅部分代码

export function downloadFile(data) {
    let downloadPath = null;

    if (data) {
        downloadPath = `${apiResource}/${data.fileName}`;
    }

    appDispatcher.dispatch({
        actionType: actionTypes.DOWNLOAD_FILE,
        downloadPath
    });
}

widgetstore.js-仅部分代码

let store = Map({
    downloadPath: null,
    isLoading: false,
    // other store properties
});

class WidgetStore extends Store {
    constructor() {
        super();
        this.dispatchToken = appDispatcher.register(action => {
            switch (action.actionType) {
                case actionTypes.DOWNLOAD_FILE:
                    store = store.merge({
                        downloadPath: action.downloadPath,
                        isLoading: !!action.downloadPath
                    });
                    this.emitChange();
                    break;
import React, {Component, PropTypes} from 'react';
import ReactDOM from 'react-dom';

function getFormInputs() {
    const {queryParams} = this.props;

    if (queryParams === undefined) {
        return null;
    }

    return Object.keys(queryParams).map((name, index) => {
        return (
            <input
                key={index}
                name={name}
                type="hidden"
                value={queryParams[name]}
            />
        );
    });
}

export default class FileDownload extends Component {

    static propTypes = {
        actionPath: PropTypes.string.isRequired,
        method: PropTypes.string,
        onDownloadComplete: PropTypes.func.isRequired,
        queryParams: PropTypes.object
    };

    static defaultProps = {
        method: 'GET'
    };

    componentDidMount() {
        ReactDOM.findDOMNode(this).submit();
        this.props.onDownloadComplete();
    }

    render() {
        const {actionPath, method} = this.props;

        return (
            <form
                action={actionPath}
                className="hidden"
                method={method}
            >
                {getFormInputs.call(this)}
            </form>
        );
    }
}

 类似资料:
  • 问题内容: 这是其中的代码 返回的响应是一个文件。我希望用户能够将其保存为文件,但是什么也没有发生。我认为服务器返回的响应类型正确,因为在控制台中它说 我想念的是什么?我应该在减速器中做什么? 问题答案: 浏览器技术当前不支持直接从Ajax请求下载文件。解决方法是添加一个隐藏的表单并将其提交到幕后,以使浏览器触发“保存”对话框。 我正在运行标准的Flux实现,因此不确定确切的Redux(Reduc

  • 我有一个API可以返回excel文档作为响应。请求将是一个简单的JSON。 我搜索了谷歌,找到了一些代码库下载文件,我已经在我的应用程序中使用了它,但我得到了一些错误,无法找到它的解决方案。下面是我的代码库。 NameService.ts HTTPService.ts 使用上面的代码库,我得到了以下两个错误,文件没有下载。 null

  • 问题内容: 我正在尝试使浏览器下载从ajax响应接收到的pdf文件。 受jquery ajax下载pdf文件启发,我模拟了如下单击/下载事件: 不幸的是,这仅适用于Chrome,不适用于Firefox + IE。当我尝试在最后两个浏览器中触发它时,没有任何反应。 由于从CMS继承,脚本和标记被放置在iframe中,但是我不确定这是否有影响。 关于如何针对所有现代浏览器进行优化的想法? 问题答案:

  • 问题内容: 我正在使用AngularJS和Spring编写应用程序。我想将请求发送到服务器,并将控制器返回的响应下载为文件。在控制器中,我有csv文件的内容(作为字符串),即(1行4列)。将此响应下载为文件的最简单方法是什么? 下面,我发布了我的简化代码。在Spring控制器中: 在javascript(AngularJS)中 我也在尝试(在下面)写入响应流,设置标头,但是在客户端,我总是以字符串

  • 我正在使用AngularJS和Spring编写应用程序。我想向服务器发送请求,并下载控制器返回的响应作为文件。在控制器中,我有csv文件的内容(作为字符串),即<代码>1;2.3.4(1行4列)。将此响应下载为文件的最简单方法是什么? 下面,我发布了我的简化代码。Spring控制器: 在javascript中(AngularJS) 我还试图写入响应流(如下所示),设置标题,但在客户端,我总是以字符

  • fetch 方法允许去跟踪 下载 进度。 请注意:到目前为止,fetch 方法无法跟踪 上传 进度。对于这个目的,请使用 XMLHttpRequest,我们在后面章节会讲到。 要跟踪下载进度,我们可以使用 response.body 属性。它是 ReadableStream —— 一个特殊的对象,它可以逐块(chunk)提供 body。在 Streams API 规范中有对 ReadableStr