救助: 前端根据 api 请求后端返回数据,并把数据导出成 csv。现在的问题在后端返回的数据很多,会导致传输时间久,并且有可能会导致浏览器崩溃,实践中有没有什么好的办法去实现这种大数量的导出 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a Javascript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
Javascript 权威指南第 5 版
Closure: The Definitive Guide
howells
V2EX    Javascript

救助: 前端根据 api 请求后端返回数据,并把数据导出成 csv。现在的问题在后端返回的数据很多,会导致传输时间久,并且有可能会导致浏览器崩溃,实践中有没有什么好的办法去实现这种大数量的导出

  •  
  •   howells 2021-02-23 14:16:20 +08:00 4828 次点击
    这是一个创建于 1692 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前端根据 api 请求后端返回数据,并把数据导出成 csv 。现在的问题在后端返回的数据很多,会导致传输时间久,并且有可能会导致浏览器崩溃,实践中有没有什么好的办法去实现这种大数量的导出。

    37 条回复    2021-02-24 16:36:12 +08:00
    lemonada
        1
    lemonada  
       2021-02-23 14:19:48 +08:00
    为啥不是后端生成 csv,给个地址前端让浏览器获取下载链接然后下载呢
    waiaan
        2
    waiaan  
       2021-02-23 14:19:55 +08:00
    后端直接生成文件
    howells
        3
    howells  
    OP
       2021-02-23 14:23:44 +08:00
    @lemonada 因为最开始数据量少的时候,就直接去拿了,然后前端根据组件去导出了,所以现在量大了之后,就还是在沿用这个思路。直接生成文件,我试试
    fucUup
        4
    fucUup  
       2021-02-23 15:17:41 +08:00 via Android
    Indexeddb 就是这个
    azcvcza
        5
    azcvcza  
       2021-02-23 15:18:14 +08:00
    1,分页去获取喽,一次拿一点,拿到最后自己拼起来 2,直接下 csv 文件
    nbhaohao
        6
    nbhaohao  
       2021-02-23 15:20:28 +08:00   2
    新增一个 “下载中心” 模块,每次生成文件就是发请求到后端,后端负责创建一个生成文件的内容。
    然后前端可以去“下载中心”去下载已经生成好的文件。
    jydeng
        7
    jydeng  
       2021-02-23 15:24:38 +08:00
    赞同 6L,加一个下载模块,后端生成完了,通过聊天工具通知。
    admin7785
        8
    admin7785  
       2021-02-23 15:39:17 +08:00 via iPhone
    后端生成文件,可以参考 Easyexcel 工具,导出很方便
    howells
        9
    howells  
    OP
       2021-02-23 16:09:16 +08:00
    @nbhaohao 这个生成的文件就还得存储下来是不,然后等你去点击下载?
    Python77
        10
    Python77  
       2021-02-23 16:10:34 +08:00
    后端生成文件
    NikoXu
        11
    NikoXu  
       2021-02-23 16:12:32 +08:00
    返回文件流不就行了 ,没必要保存成文件吧
    howells
        12
    howells  
    OP
       2021-02-23 16:14:16 +08:00
    @NikoXu 我想的是他这种设计是因为生成文件时间久,如果能直接生成文件流,应该就不用还多一个下载中心吧
    NikoXu
        13
    NikoXu  
       2021-02-23 16:17:59 +08:00
    文件流直接可以下载了
    howells
        14
    howells  
    OP
       2021-02-23 16:22:50 +08:00
    @NikoXu 不矛盾,能快速生成文件流,它就可以直接在点下载的,我根据的 6L 的方案 =》“每次生成文件就是发请求到后端,后端负责创建一个生成文件的内容” 我说这个是不是要保存下来,然后在去下载中心点下载,
    676529483
        15
    676529483  
       2021-02-23 16:25:36 +08:00
    其实只要后端实现个接口,设置请求头,返回文件流,前端标记为 download,浏览器就自动流下载流
    nbhaohao
        16
    nbhaohao  
       2021-02-23 16:26:28 +08:00
    @howells 是的,比如后端还可以做别的需求,例如文件只保留 7 天,然后前端去点击下载,下载的时候只要能拿到文件地址就可以了,比如一个 oss 地址。

    同时第一次点击“生成文件”的时候,后端的接口可以快速返回 response,即告诉用户,这个导出任务已经在执行了,然后接口慢慢去生成就可以了。
    nbhaohao
        17
    nbhaohao  
       2021-02-23 16:28:49 +08:00   1
    @howells 总结下来就是,“文件生成”的逻辑不要放在前端。
    其他答主的说法也都是对的,
    文件小的话,后端直接返回文件流,或者返回一个 url,然后前端下载就好了,
    文件大的话,最好考虑“下载中心”,就是先让这个请求快速结束,而不是强迫用户一定要开着浏览器慢慢等那个文件生成完毕。
    someonedeng
        18
    someonedeng  
       2021-02-23 17:05:02 +08:00
    还不如让后端做个导出,分分钟的事,返回文件流或对象储存连接都行
    w504391883
        19
    w504391883  
       2021-02-23 17:08:42 +08:00
    直接前台下载文件流,不要在代码中打开
    ivanshaoaz
        20
    ivanshaoaz  
       2021-02-23 17:09:54 +08:00
    做成异步任务也行 后端生成文件 前端轮训文件生成结果 后端生成文件成功返回个下载链接
    xiangyuecn
        21
    xiangyuecn  
       2021-02-23 17:12:59 +08:00
    参考 #15 楼,后端什么都不用干,响应头都不用动,前端把接口的调用改成浏览器自己去下载处理就目测 ok 了。

    最简单的办法: 把原有的 api 地址 直接粗暴的扔给 a[download] 标签手动 click 一下去触发浏览器去下载这个 url 的数据
    4771314
        22
    4771314  
       2021-02-23 17:15:19 +08:00
    肯定后端生成文件啊
    数据量大一点,前端就会卡住,很不友好
    后端可以异步生成文件,生成后通知前端去下载就可以了
    iikebug
        23
    iikebug  
       2021-02-23 17:23:36 +08:00
    webworker 或者 wasm 也可以考虑下
    Hilong
        24
    Hilong  
       2021-02-23 17:28:00 +08:00
    起一个 worker 来处理这个
    fengbjhqs
        25
    fengbjhqs  
       2021-02-23 18:14:08 +08:00
    kpi 怎么能让, 起个 worker 多线程来搞哇,除非内存泄露,请求超时可以让后端分批给数据
    Justin13
        26
    Justin13  
       2021-02-23 18:41:18 +08:00 via Android
    后端上 worker 导出 csv,成功后前端获取下载的 url 。点击下载。
    jones2000
        27
    jones2000  
       2021-02-23 20:37:44 +08:00
    生成文件同步到 CND 或云盘,然后下载就可以了。
    xieranmaya
        28
    xieranmaya  
       2021-02-23 21:05:13 +08:00
    流式处理。前端现在是可以实现的。
    golangLover
        29
    golangLover  
       2021-02-23 21:22:42 +08:00
    返回文件流+1
    golangLover
        30
    golangLover  
       2021-02-23 21:23:14 +08:00
    然后 header 是 attachment
    hantsy
        31
    hantsy  
       2021-02-23 21:33:40 +08:00
    生成临时文件(用 Redis 之类的,或者缓存工具,定时删除),数据源就稳定了。直接 Expose 这个文件给 Client 就可以了。
    tokyo2020
        32
    tokyo2020  
       2021-02-23 21:34:32 +08:00
    我的想法是 前端肯定有些参数列表,调 api 请求数据 getData 呢,后端可以先返回一个 queryId 。 大约 10s 后,前端带着 queryId 调用 api 再问询下, 后端服务器如果处理好了后,还可以把 queryId 的内容缓存下来呢。
    hantsy
        33
    hantsy  
       2021-02-23 21:35:10 +08:00
    另外写文件到 FTP 目录,客户端用 FTP 协议获取。

    银行支付行业,对账很多用 FTP 协议,定时处理。
    xuanbg
        34
    xuanbg  
       2021-02-24 08:59:58 +08:00
    后端导出文件并上传 oss,前端轮询结果,或者刷列表(需要实现一个导出文件管理功能)。
    wakzz
        35
    wakzz  
       2021-02-24 11:49:00 +08:00
    一般是两个方案
    1. 文件流:后端给前端传文件流,前端只要把流存成文件就可以了
    2. 异步文件: 后端异步生成文件,直接给前端一个最终文件的下载地址
    rodrick
        36
    rodrick  
       2021-02-24 11:57:29 +08:00
    文件流下载学到了
    zhuweiyou
        37
    zhuweiyou  
       2021-02-24 16:36:12 +08:00
    后端异步生成, 存到 OSS.

    前端轮询状态, 完成后 出现下载按钮.
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2731 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 07:35 PVG 15:35 LAX 00:35 JFK 03:35
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86