讲解在同名B/D上都有,主要介绍一些跟业务无关的代码技巧
注: 在CodeReview中,部分内容主观性较大,一家之言姑且听之
本文主要介绍下载出现的"白屏"问题
业务抽象
后端代码
const express = require('express');
const app = express();
const xlsx = require('node-xlsx').default;
app.use(express.static('public'))
const api = () => new Promise(resolve => {
setTimeout(() => {
resolve([
['zh-CN', 'en'],
])
}, 5000)
});
// 动态生成excel/pdf/world/压缩包等资源文件
app.get('/excel', async (req, res) => {
res.setHeader('Content-Type', 'application/xlsx')
res.setHeader('Content-Disposition', 'attachment;filename=demo.xlsx')
// 模拟 获取数据
const data = await api();
const buffer = xlsx.build([{ name: 'mySheetName', data: data }]);
res.send(buffer); // json格式
})
app.listen(3000, () => { })
前端代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button onclick="window.location.href='/excel'">下载1</button>
<button onclick="download()">下载2</button>
<script>
function download() {
window.open("/excel")
}
</script>
</body>
</html>
交互问题
href切换
浏览器输入框后回车,与ajax是不一样的,浏览器输入地址类型属于document
,是三个documentLoader切换的过程,第一个documentLoader
做拦截,第二个documentLoader
发送请求,此时浏览器左上角进入loading状态,但可以随时取消,接收到数据后,才会进入到第三个documentLoader
,根据content-type
决定"渲染器",这里指进入到下载器里面
window.open 新建
遇上一个问题原理一样,但因为不需要渲染,最后会自动关闭
解决方案
flushHeader
先介绍正经的方案,flushHeader提前发送header即可
const express = require('express');
const app = express();
const xlsx = require('node-xlsx').default;
app.use(express.static('public'))
const api = () => new Promise(resolve => {
setTimeout(() => {
resolve([
['zh-CN', 'en'],
])
}, 5000)
});
// 动态生成excel/pdf/world/压缩包等资源文件
app.get('/excel', async (req, res) => {
res.setHeader('Content-Type', 'application/xlsx')
res.setHeader('Content-Disposition', 'attachment;filename=demo.xlsx')
res.flushHeaders()
// 模拟 获取数据
const data = await api();
const buffer = xlsx.build([{ name: 'mySheetName', data: data }]);
res.end(buffer);
})
app.listen(3000, () => { })
href
点击以后直接进入到下载流
window.open
同上,好一点,但不多,第7下还是会出现,但跟这个方案没有关系,猜下原因 /dog
原因
服务器响应时间
document的解析原理上面已经提到过了,里面包含一个关键数据content-type
,只要能够提前获取到就可以了
当前的主流方案是send,即准备好数据后,再统一发送,所以中间的5s属于服务响应时间
资源下载时间
接收到content-type后,可以理解为接收到第一个字节后,可以选择"解析器",此时进入到内容下载阶段,当然,上图看不出来,因为后面的内容托管给下载器了,下面这个图可以看出来,我用fetch加载的
方案2
硬控
纯前端没有太好的办法,此时会硬控,比如gitee的下载提示,原因如下
没好意思下几百M的,注意服务器等待时间