我正在努力解决 HapiJS 11.1.4 的问题并用流回复以向浏览器提供文件。结果下载已损坏。
主要端点是/api/library/export
并使用 ExcelJS 生成包含 XLSX 文件数据的流,然后我将使用该文件进行回复。
此端点在使用 Curl 访问时按预期工作,并且不会发生损坏。这纯粹是我遇到问题的浏览器。
/api/library/export
端点代码:
handle(request, reply) {
// Invoke XLSX generation and reply
mapRecordsToXlsx(xlsxOpts).then(stream => {
console.log(stream.length);
return reply(stream)
// .type('application/octet-stream')
// .type('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
// .header('Content-Disposition', 'attachment; filename=library-export.xlsx;')
// .header('Content-Length', stream.length)
// .encoding('binary')
// .encoding(null)
});
}
如您所见,我尝试了各种响应标头组合,但均无济于事。
代码mapRecordsToXlsx
:
export function mapRecordsToXlsx(opts) {
const workbook = new Excel.stream.xlsx.WorkbookWriter();
workbook.created = new Date();
workbook.modified = new Date();
// Iterate through each set of mappings and records
opts.forEach(({title, mappings, types, records}) => {
// Create a worksheet for the current set
const sheet = workbook.addWorksheet(title);
// Set column headers from mapping
const headers = Object.keys(mappings);
sheet.columns = headers.map(header => {
return { header, key: mappings[header] };
});
// Generate rows for each record in the current sheet
records.forEach(record => {
const row = {};
headers.forEach(header => {
let value = _.get(record, mappings[header]);
// Detect custom types and apply appropriate transformations
if (types[header]) {
switch (types[header]) {
case 'date':
value = new Date(Date.parse(value)); // ExcelJS wants a Date object
break;
default:
break;
}
}
row[mappings[header]] = value;
});
sheet.addRow(row).commit();
});
sheet.commit();
});
return workbook.commit().then(() => {
return workbook.stream.read();
});
}
而且,在接收方(EmberJS):
exportAll() {
const searchString = this.get('searchString');
if (searchString.length > 0) {
this.set('loading', true);
this.get('library').exportAll(searchString)
.then(xlsx => {
this.set('loading', false);
const fileName = `Library - ${searchString}.xlsx`;
// Hack to force download of file
const a = document.createElement('a');
document.body.appendChild(a);
a.style = 'display: none';
const blob = new Blob([xlsx], {type: 'octet/stream'});
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
window.URL.revokeObjectURL(url);
return a.parentNode.removeChild(a);
});
}
}
this.get('library').exportAll(searchString)
纯粹是一个抽象,Ember.$.ajax()
将解析/拒绝作为一个承诺。
结果文件的比较,浏览器(左)与 curl(右):
编码看起来不对,但我不知道它是如何发生的。
这也可以帮助您帮助我:
HTTP/1.1 200 OK
vary: origin,accept-encoding
access-control-allow-origin: http://localhost:4200
access-control-expose-headers: WWW-Authenticate,Server-Authorization
content-type: application/octet-stream
cache-control: no-cache
content-length: 10157
accept-ranges: bytes
Date: Tue, 15 Aug 2017 13:49:50 GMT
Connection: keep-alive
Content-Length 与 HapiJS 记录的内容相匹配。