Nodejs Express下载文件,并保存成原文件
现时需要开发一个Excel下载功能
后台有一个API,负责接收传入的JSON文件,生成带图片的Excel文件在临时目录(生成Excel使用npm exceljs库),并将文件通过Router返回
前台Client调用后台API,读取文件流生成Excel文件下载

API生成Excel文件代码
const getLinePlanExcelJson = (data) => {
// let workBook;
//workbook properties
var workBook = new exceljs.Workbook();
workBook.creator = 'Esquel LPD Project';
workBook.lastModifiedBy = 'Esquel LPD Project';
workBook.created = new Date();
workBook.modified = new Date();
return new Promise((resolve, reject) => {
if (typeof (data.customerCode) === 'undefined' || typeof (data.linePlanProducts) === 'undefined') {
reject(new Error('{"Error Message":"incorrect format."}'));
}
//base var
let mc_productStyles = data.productStyles;
let mc_productFabrics = data.productFabrics;
let mc_productTrims = data.productTrims;
//---------------------------
let workSheet_name = "LinePlan";
// create worksheet
let workSheet = workBook.addWorksheet(workSheet_name, {
// properties: {
// tabColor: { argb: 'FFC0000' }
// },
// pageSetup: {
// paperSize: 50,
// orientation: 'landscape'
// }
});
//setting header title
let headerTitleArray = config.LinePlan.columns;
let headerColumns = [];
for (let headerIndex = ; headerIndex < headerTitleArray.length; headerIndex++) {
headerColumns.push({
header: headerTitleArray[headerIndex].title,
key: 'col' + headerIndex,
width: headerTitleArray[headerIndex].width
});
}
//setting header to worksheet
workSheet.columns = headerColumns;
//setting auto filter
workSheet.autoFilter = {
from: 'A1',
to: 'AA1'
}
//----------------------------------------------------
//col index
let colIndex = ;
let rowIndex = ;
data.linePlanProducts.map((linePlanProduct) => {
//get style data
let find_StyleData = _.where(mc_productStyles, { styleID: linePlanProduct.productID });
linePlanProduct.productMaterialConfigs.map((colorway) => {
//reset col index
colIndex = ;
let newrow = [];
//style id---------------------------------------
newrow[colIndex] = linePlanProduct.productID;
//style image---------------------------------------
colIndex++;
newrow[colIndex] = find_StyleData[].imageURL ? find_StyleData[].imageURL : '';
// cell = { v: find_StyleData[0].imageURL, t: 's', l: { Target: find_StyleData[0].imageURL, Tooltip: linePlanProduct.productID } };
// //colorway body fabirc image---------------------------------------
colIndex++;
newrow[colIndex] = colorway.PrimaryFabricImageUrl ? colorway.PrimaryFabricImageUrl : '';
// cell = { v: colorway.PrimaryFabricImageUrl, t: 's', l: { Target: colorway.PrimaryFabricImageUrl, Tooltip: colorway.primaryFabricID } };
//matching---------------------------------------
colIndex++;
//colorway body fabirc item code---------------------------------------
colIndex++;
newrow[colIndex] = colorway.primaryFabricID;
//colorway body fabirc info---------------------------------------
let find_FabricData = _.where(mc_productFabrics, { fabricID: colorway.primaryFabricID });
colIndex++;
newrow[colIndex] = find_FabricData[].longDescriptions[] ? find_FabricData[].longDescriptions[] : '';
// //colorway body fabirc content---------------------------------------
colIndex++;
newrow[colIndex] = find_FabricData[].longDescriptions[] ? find_FabricData[].longDescriptions[] : '';
// //fabric width---------------------------------------
colIndex++;
newrow[colIndex] = find_FabricData[].longDescriptions[] ? find_FabricData[].longDescriptions[] : '';
//button colour---------------------------------------
colIndex++;
// // let find_trims = _.where(colorway.appliedAuxiliaries, { auxiliaryType: 'T' });
// // let find_fabrics = _.where(colorway.appliedAuxiliaries, { auxiliaryType: 'F' });
// //button1 item code---------------------------------------
colIndex++;
newrow[colIndex] = colorway.appliedAuxiliaries[] ? colorway.appliedAuxiliaries[].auxiliaryID : '';
//button2 item code---------------------------------------
colIndex++;
newrow[colIndex] = colorway.appliedAuxiliaries[] ? colorway.appliedAuxiliaries[].auxiliaryID : '';
//button3 item code---------------------------------------
colIndex++;
newrow[colIndex] = colorway.appliedAuxiliaries[] ? colorway.appliedAuxiliaries[].auxiliaryID : '';
//button4 item code---------------------------------------
colIndex++;
newrow[colIndex] = colorway.appliedAuxiliaries[] ? colorway.appliedAuxiliaries[].auxiliaryID : '';
// //style fit---------------------------------------
colIndex++;
newrow[colIndex] = linePlanProduct.fitName;
//style collection---------------------------------------
colIndex++;
newrow[colIndex] = linePlanProduct.collectionName ? linePlanProduct.collectionName + ' Collection' : '';
//style gender---------------------------------------
colIndex++;
newrow[colIndex] = linePlanProduct.gender;
//fabric---------------------------------------
colIndex++;
newrow[colIndex] = find_FabricData[].longDescriptions[] ? find_FabricData[].longDescriptions[] : '';
//style collar---------------------------------------
colIndex++;
newrow[colIndex] = linePlanProduct.collarName;
//style sleeve---------------------------------------
colIndex++;
newrow[colIndex] = linePlanProduct.sleeveName;
//style cuff---------------------------------------
colIndex++;
newrow[colIndex] = linePlanProduct.cuffName;
//style washing---------------------------------------
colIndex++;
//style pocket---------------------------------------
colIndex++;
newrow[colIndex] = linePlanProduct.pocketName;
//colorway body pattern pocket---------------------------------------
colIndex++;
newrow[colIndex] = colorway.bodyPattern;
//colorway body color name---------------------------------------
colIndex++;
//colorway name---------------------------------------
colIndex++;
newrow[colIndex] = colorway.colorway;
//colorway plu---------------------------------------
colIndex++;
newrow[colIndex] = colorway.pluNumber
//colorway market---------------------------------------
let marketArray = [];
colorway.markets.map((market) => {
marketArray.push(market.marketCode);
});
colIndex++;
newrow[colIndex] = marketArray ? marketArray.join('/') : '';
workSheet.addRow(newrow).commit();
//setting row style
// let row = workSheet.lastRow;
// row.height = 120;
rowIndex++;
});
});
//need retry array
let all_needProcessCellArray = [];
let firsttime_faild_cellArray = [];
let secendtime_faild_cellArray = [];
//define add image function
let fetchImageFun = function (workSheet, cell, CellArray) {
return new Promise((resolve, reject) => {
if (!cell.value) resolve('no');
// let starttime = new Date();
request.get({ url: cell.value, encoding: null, timeout: }, function (error, response, body) {
if (error) {
// let endtime = new Date();
// console.log(cell.address + ' Faild ' + starttime + ' ' + endtime);
if (CellArray) CellArray.push(cell);
resolve('err');
}
if (body) {
if (response.statusCode === ) {
console.log('load image error from url:' + cell.value);
} else if (response.statusCode === ) {
console.log('can not load image from url:' + cell.value);
}
//get image
let imageObject = workBook.addImage({
buffer: new Buffer(body),
extension: response.headers["content-type"]
});
//add image to cell
let imageCellName = cell.address + ':' + cell.address;
workSheet.addImage(imageObject, imageCellName);
//clear value
cell.value = '';
resolve('ok');
}
});
});
}
let functionArray = [];
//add image to cell
workSheet.eachRow({ includeEmpty: true }, function (row, rowNumber) {
if (rowNumber > ) {
row.height = ;
row.eachCell({ includeEmpty: true }, function (cell, colNumber) {
cell.alignment = { vertical: 'top', horizontal: 'left' };
// cell.border = {
// top: { style: 'thin', color: { argb: 'FFFFFF00' } },
// left: { style: 'thin', color: { argb: 'FFFFFF00' } },
// bottom: { style: 'thin', color: { argb: 'FFFFFF00' } },
// right: { style: 'thin', color: { argb: 'FFFFFF00' } }
// };
//add image is work
if (colNumber === || colNumber === ) {
all_needProcessCellArray.push(cell);
}
});
}
});
all_needProcessCellArray.forEach((getCell) => {
functionArray.push(fetchImageFun(workSheet, getCell, firsttime_faild_cellArray));
});
//add function to array
//resolve function
Promise.all(functionArray)
.then((result) => {
if (firsttime_faild_cellArray) {
firsttime_faild_cellArray.forEach((getCell) => {
functionArray.push(fetchImageFun(workSheet, getCell, secendtime_faild_cellArray));
});
//first time retry
Promise.all(functionArray)
.then((result2) => {
if (secendtime_faild_cellArray) {
secendtime_faild_cellArray.forEach((getCell) => {
functionArray.push(fetchImageFun(workSheet, getCell));
});
//secend time retry
Promise.all(functionArray)
.then((result2) => {
resolve(workBook);
}).catch((err3) => {
reject(null);
});
} else {
resolve(workBook);
}
}).catch((err2) => {
reject(null);
});
} else {
resolve(workBook);
}
}).catch((err) => {
reject(null);
})
});
}
API路由代码
let express = require('express');
let genCSV = require("./genCSV.js");
let exceljs = require('exceljs');
let util = require('util');
let fs = require('fs');
let router = express.Router();
//post data to router
router.post('/', function (req, res, next) {
genCSV.getLinePlanExcelJson(req.body)
.then((excelObject) => {
// throw new Error('this is test error');
//return to client
let fileName = 'LinePlan-' + req.body.linePlanID + '.xlsx';
let filePath = './public/temp/' + fileName;
if (fs.existsSync(filePath)) {
fs.unlink(filePath);
}
excelObject.xlsx.writeFile(filePath, { bookType: 'xlsx', bookSST: false, type: 'buffer' })
.then(() => {
res.status().download(filePath, fileName);
}).catch((err) => {
throw err
});
})
.catch((err) => {
res.status().end('{"err":"' + err.message + '"}');
});
});
module.exports = router;
前台Client调用代码
fetchMethodExcel: function (apiName, method, requestObject, requestBody, callback) {
fetch3(this.apiExport(apiName, requestObject), {
// method: method,
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody),
})
.then((data) => {
if (data.status === ) {
throw new Error('Explort LinePlan API Error');
} else if (data.status === ) {
throw new Error('Can Not Found Explort LinePlan API');
}
return data.blob();
})
.then((blob) => {
let a = document.createElement('a');
let url = window.URL.createObjectURL(blob);
let filename = 'LinePlan-' + requestBody.linePlanID + '.xlsx';
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
callback();
})
.catch(err => {
callback(err);
});
}
运行结果是
但是下载的文件却是无法打开的,一直说是文件有内容有问题,尝试恢复很久都没有返回。


解除锁定后,可以正常打开文件了

Nodejs Express下载文件,并保存成原文件的更多相关文章
- tcpdump抓包并保存成cap文件
首选介绍一下tcpdump的常用参数 tcpdump采用命令行方式,它的命令格式为: tcpdump [ -adeflnNOpqStvx ] [ -c 数量 ] [ -F 文件名 ] [ -i 网络接 ...
- Atitit.软件开发概念说明--io系统区--特殊文件名称保存最佳实践文件名称编码...filenameEncode
Atitit.软件开发概念说明--io系统区--特殊文件名称保存最佳实践文件名称编码...filenameEncode 不个网页title保存成个个文件的时候儿有无效字符的问题... 通常两个处理方式 ...
- linux批量压缩当前目录中文件后,删除原文件
linux批量压缩当前目录中文件后,删除原文件 for i in `ls|awk -F " " '{print $NF}'`; do tar -zcvf $i.tar.gz $i ...
- matrix-gui-2.0 将javascript文件夹改成js文件夹
/******************************************************************************** * matrix-gui-2.0 将 ...
- 把ANSI格式的TXT文件批量转换成UTF-8文件类型
把ANSI格式的TXT文件批量转换成UTF-8文件类型 Posted on 2010-08-05 10:38 moss_tan_jun 阅读(3635) 评论(0) 编辑 收藏 #region 把AN ...
- opencv::将两幅图像合并后,在同一个窗口显示;并将合并的图像流保存成视频文件
/** * @file main-opencv.cpp * @date July 2014 * @brief An exemplative main file for the use of ViBe ...
- [转载] 与WIN不同,linux替换文件夹会删除原文件夹下的全部内容!
今天差点把源码给覆盖掉了><...555... 虚惊一场!!看了一篇博客分析这种情况.我的环境是CentOS5.5,不会出现文件夹直接被覆盖的情况,但是在Linux下不要用Win下的一些直 ...
- 关于jmeter+ant+jenkins性能自动化将测试结果文件jtl转换成html文件遇到的问题。
1.ant自身缺陷,返回结果中有特殊字符,乱码字符,无法识别,jtl文件转换时报错. 2.jtl文件过大转换成html文件时出现内存溢出. 针对以上情况:可考虑使用BeenShell Sampler: ...
- py文件加密打包成exe文件
python的py.pyc.pyo.pyd文件区别 py是源文件: pyc是源文件编译后的文件: pyo是源文件优化编译后的文件: pyd是其他语言写的python库: 为什么选用Cpython .p ...
随机推荐
- 【python】Python 字典(Dictionary)操作详解
Python字典是另一种可变容器模型,且可存储任意类型对象,如字符串.数字.元组等其他容器模型.一.创建字典字典由键和对应值成对组成.字典也被称作关联数组或哈希表.基本语法如下: dict = {'} ...
- 多线程 定时器 Timer TimerTask
定时器是一种特殊的多线程,使用Timer来安排一次或者重复执行某个任务 package org.zln.thread; import java.util.Date; import java.util. ...
- Luogu 3435 POI2006OKR-Periods of Words(kmp)
显然答案应该是Σi-next[next[……next[i]]] (next[next[……next[i]]]>0).递推即可. #include<iostream> #include ...
- [UOJ#351]新年的叶子
[UOJ#351]新年的叶子 试题描述 躲过了AlphaGo 之后,你躲在 SingleDog 的长毛里,和它们一起来到了AlphaGo 的家.此时你们才突然发现,AlphaGo 的家居然是一个隐藏在 ...
- [洛谷P3693]琪露诺的冰雪小屋
题目大意:琪露诺的冰雪小屋,我做的第一道大模拟题. 题解:模拟... 卡点:无数小错误,要是没有写一点调一点,那大概是永远调不出来了... C++ Code: #include <cstdio& ...
- 【NOIP2017 D1 T1 小凯的疑惑】
题目描述 小凯手中有两种面值的金币,两种面值均为正整数且彼此互素.每种金币小凯都有 无数个.在不找零的情况下,仅凭这两种金币,有些物品他是无法准确支付的.现在小 凯想知道在无法准确支付的物品中,最贵的 ...
- 东北育才冲刺noip(day9)
这十天来呢,感觉自己进步很大,(虽然被碾压的很惨),看到了自己以前完全没见过,也没想过的算法,打开新世界的大门. 同时呢,也感觉自己太弱了,于是就注册了这个博客. 为了促进进步,在这里立下flag,我 ...
- android脱壳之DexExtractor原理分析
导语: 上一篇我们分析android脱壳使用对dvmDexFileOpenPartial下断点的原理,使用这种方法脱壳的有2个缺点: 1. 需要动态调试 2. 对抗反调试方案 为了提高工作效率, ...
- JQuery拖拽改变元素的尺寸
"元素拖拽改变大小"其实和"元素拖拽"一个原理,只是所动态改变的对象不同而已,主要在于 top.left.width.height 的运用,相对实现起来也非常容 ...
- Join EC2 into AD with SSM and remote powershell in AWS
1.Create joinad.ps1 $username = "ad-domain\admin" $Password = "password" $pwd = ...