- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我需要允许我的应用程序的用户使用 Meteor 下载文件。目前我所做的是当用户请求下载一个文件时,我在 Mongo 中输入一个“fileRequests”集合,一个包含文件位置和请求时间戳的文档,并返回新创建的请求的 ID。当客户端获得新 ID 时,它会立即转到 mydomain.com/uploads/:id。然后我使用类似这样的东西在 Meteor 之前拦截请求:
var connect = Npm.require("connect");
var Fiber = Npm.require("fibers");
var path = Npm.require('path');
var fs = Npm.require("fs");
var mime = Npm.require("mime");
__meteor_bootstrap__.app
.use(connect.query())
.use(connect.bodyParser()) //I add this for file-uploading
.use(function (req, res, next) {
Fiber(function() {
if(req.method == "GET") {
// get the id here, and stream the file using fs.createReadStream();
}
next();
}).run();
});
我检查以确保文件请求是在不到 5 秒之前发出的,并且在我查询后立即删除请求文档。
这可行,而且我认为(足够)安全。没有人可以在未登录的情况下发出请求,5 秒对于能够劫持创建的请求 URL 的人来说是一个非常小的窗口,但我只是觉得我的解决方案不合适。感觉很脏!
所以我尝试使用 Meteor-Router完成同样的事情。这样我就可以检查他们是否正确登录,而无需进行 5 秒开放世界欺骗。
所以这是我为此编写的代码:
Meteor.Router.add('/uploads/:id', function(id) {
var path = Npm.require('path');
var fs = Npm.require("fs");
var mime = Npm.require("mime");
var res = this.response;
var file = FileSystem.findOne({ _id: id });
if(typeof file !== "undefined") {
var filename = path.basename(file.filePath);
var filePath = '/var/MeteorDMS/uploads/' + filename;
var stat = fs.statSync(filePath);
res.setHeader('Content-Disposition', 'attachment; filename=' + filename);
res.setHeader('Content-Type', mime.lookup(filePath));
res.setHeader('Content-Length', stat.size);
var filestream = fs.createReadStream(filePath);
filestream.pipe(res);
return;
}
});
这看起来很棒,与代码的其余部分完全吻合并且易于阅读,不涉及黑客攻击,但是!它不起作用!浏览器不停地旋转,永远不知道该做什么。我收到零错误消息。我可以继续在其他选项卡上使用该应用程序。我不知道它在做什么,它永远不会停止“加载”。如果我重新启动服务器,我会得到一个包含所有正确 header 的 0 字节文件,但我没有得到数据。
非常感谢任何帮助!!
编辑:
在深入研究之后,我注意到尝试将响应对象转换为 JSON 对象会导致循环结构错误。
有趣的是,当我监听“数据”事件的文件流,并尝试将响应对象字符串化时,我没有收到该错误。但是,如果我尝试在我的第一个解决方案中做同样的事情(听“数据”并将响应字符串化),我会再次收到错误。
所以使用 Meteor-Router 解决方案,响应对象发生了一些变化。我还注意到在“数据”事件上,response.finished 被标记为 true。
filestream.on('data', function(data) {
fs.writeFile('/var/MeteorDMS/afterData', JSON.stringify(res));
});
最佳答案
Meteor 路由器安装了一个中间件来进行路由。所有 Connect 中间件要么必须调用 next()
(恰好一次)以指示响应尚未确定,要么必须通过调用 res.end()
或通过管道响应。不允许两者都做。
我研究了中间件的源代码(见下文)。我们看到我们可以返回false
来告诉中间件调用next()
。这意味着我们声明这条路由没有解决响应,我们想让其他中间件完成它们的工作。
或者我们可以返回模板名称、文本、数组[status, text]
或数组[status, headers, text]
,中间件将使用我们返回的数据调用 res.end()
代表我们解决响应。
但是,通过管道响应,我们已经确定了响应。 Meteor 路由器不应调用 next()
或 res.end()
。
我们通过 fork Meteor 路由器并进行小改动解决了这个问题。我们将第 87 行中的 else
(在 if (output === false)
之后)替换为:
else if (typeof(output)!="undefined") {
查看带有 sha 8d8fc23d9c 的提交在我的 fork 里。
这样,路由方法中的return;
将告诉路由器什么都不做。当然,您已经通过管道处理响应了。
中间件的源代码与 sha f910a090ae 的提交中一样:
// hook up the serving
__meteor_bootstrap__.app
.use(connect.query()) // <- XXX: we can probably assume accounts did this
.use(this._config.requestParser(this._config.bodyParser))
.use(function(req, res, next) {
// need to wrap in a fiber in case they do something async
// (e.g. in the database)
if(typeof(Fiber)=="undefined") Fiber = Npm.require('fibers');
Fiber(function() {
var output = Meteor.Router.match(req, res);
if (output === false) {
return next();
} else {
// parse out the various type of response we can have
// array can be
// [content], [status, content], [status, headers, content]
if (_.isArray(output)) {
// copy the array so we aren't actually modifying it!
output = output.slice(0);
if (output.length === 3) {
var headers = output.splice(1, 1)[0];
_.each(headers, function(value, key) {
res.setHeader(key, value);
});
}
if (output.length === 2) {
res.statusCode = output.shift();
}
output = output[0];
}
if (_.isNumber(output)) {
res.statusCode = output;
output = '';
}
return res.end(output);
}
}).run();
});
关于node.js - 如何在 Meteor 路由器(NodeJS)中使用文件系统的 createReadStream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17073431/
我正在学习构建单页应用程序 (SPA) 所需的所有技术。总而言之,我想将我的应用程序实现为单独的层,其中前端仅使用 API Web 服务(json 通过 socket.io)与后端通信。前端基本上是
当我看到存储在我的数据库中的日期时。 这是 正常 。日期和时间就是这样。 但是当我运行 get 请求来获取数据时。 此格式与存储在数据库 中的格式不同。为什么会发生这种情况? 最佳答案 我认为您可以将
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在尝试使用backbone.js 实现一些代码 和 hogan.js (http://twitter.github.com/hogan.js/) Hogan.js was developed ag
我正在使用 Backbone.js、Node.js 和 Express.js 制作一个 Web 应用程序,并且想要添加用户功能(登录、注销、配置文件、显示内容与该用户相关)。我打算使用 Passpor
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 8 年前。 Improve this ques
我尝试在 NodeJS 中加载数据,然后将其传递给 ExpressJS 以在浏览器中呈现 d3 图表。 我知道我可以通过这种方式加载数据 - https://github.com/mbostock/q
在 node.js 中,我似乎遇到了相同的 3 个文件名来描述应用程序的主要入口点: 使用 express-generator 包时,会创建一个 app.js 文件作为生成应用的主要入口点。 通过 n
最近,我有机会观看了 john papa 关于构建单页应用程序的精彩类(class)。我会喜欢的。它涉及服务器端和客户端应用程序的方方面面。 我更喜欢客户端。在他的实现过程中,papa先生在客户端有类
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我是一个图形新手,需要帮助了解各种 javascript 2D 库的功能。 . . 我从 Pixi.js 中得到了什么,而我没有从 Konva 等基于 Canvas 的库中得到什么? 我从 Konva
我正在尝试将一些 LESS 代码(通过 ember-cli-less)构建到 CSS 文件中。 1) https://almsaeedstudio.com/ AdminLTE LESS 文件2) Bo
尝试查看 Express Passport 中所有登录用户的所有 session ,并希望能够查看当前登录的用户。最好和最快的方法是什么? 我在想也许我可以在登录时执行此操作并将用户模型数据库“在线”
我有一个 React 应用程序,但我需要在组件加载完成后运行一些客户端 js。一旦渲染函数完成并加载,运行与 DOM 交互的 js 的最佳方式是什么,例如 $('div').mixItUp() 。对
请告诉我如何使用bodyparser.raw()将文件上传到express.js服务器 客户端 // ... onFilePicked(file) { const url = 'upload/a
我正在尝试从 Grunt 迁移到 Gulp。这个项目在 Grunt 下运行得很好,所以我一定是在 Gulp 中做错了什么。 除脚本外,所有其他任务均有效。我现在厌倦了添加和注释部分。 我不断收到与意外
我正在尝试更改我的网站名称。找不到可以设置标题或应用程序名称的位置。 最佳答案 您可以在 config/ 目录中创建任何文件,例如 config/app.js 包含如下内容: module.expor
经过多年的服务器端 PHP/MySQL 开发,我正在尝试探索用于构建现代 Web 应用程序的新技术。 我正在尝试对所有 JavaScript 内容进行排序,如果我理解得很好,一个有效的解决方案可以是服
我是 Nodejs 的新手。我在 route 目录中有一个 app.js 和一个 index.js。我有一个 app.use(multer....)。我还定义了 app.post('filter-re
我正在使用 angular-seed用于构建我的应用程序的模板。最初,我将所有 JavaScript 代码放入一个文件 main.js。该文件包含我的模块声明、 Controller 、指令、过滤器和
我是一名优秀的程序员,十分优秀!