【发布时间】:2016-02-12 00:17:44
【问题描述】:
我的节点服务器正在生成一个 json 对象/数组。我需要将其发送给用户,但不是显示在浏览器上,而是作为文件显示。我该怎么做?
我不认为将其写入文件然后使用res.sendFile() 是正确的做法。
【问题讨论】:
我的节点服务器正在生成一个 json 对象/数组。我需要将其发送给用户,但不是显示在浏览器上,而是作为文件显示。我该怎么做?
我不认为将其写入文件然后使用res.sendFile() 是正确的做法。
【问题讨论】:
您只需添加标题Content-Type 作为浏览器不会直接显示的内容,然后内容将作为附件下载。
如果要命名下载文件,则必须使用标题Content-Disposition。
JSON 对象可以简单地转换为字符串并与以上两个标头一起发送。
以下是工作服务器代码。
http = require('http');
server = http.createServer( function(req, res) {
/**************** This is the important part **************/
res.writeHead(200, {
'Content-Type': 'application/json-my-attachment',
"content-disposition": "attachment; filename=\"my json file.json\""
});
var jsonObj = {"name":"Will McAvoy"};
res.end(JSON.stringify(jsonObj));
});
port = 3000;
host = '127.0.0.1';
server.listen(port, host);
console.log('Listening at http://' + host + ':' + port);
application/json-my-attachment是一个编造的Content-Type名称,由于浏览器无法识别它,它会尝试下载它。否则你也可以添加标准头Content-Type: application/octet-stream。
编辑
关于第二个问题,下载文件时如何在POST请求中发送参数,可以使用HTML Form轻松完成。
当您使用AngularJS 时,我假设您不希望通过提交表单来刷新页面。这可以使用IFrame 来完成。只需使用 Javascript 将 IFrame 的 src 属性更新为文件下载路径即可。
它解决了页面刷新问题,但我们无法仅使用 IFrame 发送 POST 请求 with body。
这里我们必须使用combination of Form and IFrame。 HTML 表单有一个属性target,我们可以在其中指定 IFrame 的名称。 Form 可以指定要使用的表单参数、动作和 HTTP 方法。由于目标是 IFrame,因此不会刷新当前页面。
注意:此方法的局限性在于,虽然有一些hacks available,但您不能随表单提交一起发送HTTP标头。
以下是工作代码。我使用Expressjs作为节点服务器。
HTML
<button id="downloadFile">download file</button>
<form id="downloadForm" method="post" action="http://localhost:3000/download" target="downloadIframe" style="display:none">
<input type="text" name="param1">
<input type="text" name="param2">
</form>
<iframe id="downloadIframe" name="downloadIframe" style="display:none"/>
Javascript
$(function () {
$("#downloadFile").click(function () {
var form = $("#downloadForm");
form.find("[name=param1]").val("hello");
form.find("[name=param2]").val("world");
form.submit();
});
});
NPM 安装
npm install express
npm install body-parser
节点服务器
var express = require('express');
var bodyParser = require('body-parser');
var path = require('path');
var fs = require('fs');
app = express(),
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
port = process.env.PORT || 3000;
app.all("/*", function (req, res) {
if(req.method = "POST" && req.url === "/download") {
/**************** This is the important part **************/
res.writeHead(200, {
'Content-Type': 'application/json-my-attachment',
"content-disposition": "attachment; filename=\"my json file.json\""
});
console.log("body : " + JSON.stringify(req.body));
var jsonObj = {"name":"Will McAvoy"};
res.end(JSON.stringify(jsonObj));
} else {
var filePath = req.url;
filePath = (filePath === "/") ? "index.html" : filePath;
filePath = path.join(__dirname, "public", filePath);
console.log(filePath);
fs.stat(filePath, function (err, stat) {
if(!err) {
res.sendFile(filePath);
} else {
res.writeHead(404);
res.end("file not found");
}
});
}
});
console.log("server started at : http://localhost:" + port);
app.listen(port);
** 点击下载按钮时的服务器输出**
服务器开始于:http://localhost:3000
正文:{"param1":"hello","param2":"world"}
【讨论】: