移动服务 + DocumentDB 附件
Mobile Service + DocumentDB attachment
这是我的堆栈:
iOS 和 Android 应用程序
文档数据库
Javascript
支持的移动服务
Javascript
支持的 Azure 站点
我想要做的是从我们的应用程序中提取 DocumentDB 的知识,因为我们正在构建白标签解决方案,我们可能需要 on-the-fly 扩展 DocumentDB 实例。使用抽象类型的服务,我们基本上可以根据从应用程序发送的某些数据来分片我们的 docdb 实例。
现在这将包含 2 个操作,我想为其创建移动服务。一个用于获取 JSON 数据,另一个用于获取与文档关联的附件。这就是我的麻烦所在。我有一个仅用 NodeJS 编写的可部署的 pass-through 服务。我喜欢与移动服务相关的安全模型,所以我想调整我的代码以适应它。问题在于通过管道将 DocDB 响应传递给移动服务响应。首先是移动服务默认值 headers 试图设置但失败了,所以我暂时覆盖了该功能。现在移动服务从不响应,直到发生超时。这是一个代码片段:
exports.get = function (req, res) {
...
// .then().fail() always pushed into the fail() block, but if I use the 2 function in .then() way it works.
client.readMediaAsync(mediaUrl).then(
// Success
function (media) {
// Set up caching and proxy the response
media.headers["cache-control"] = "max-age=2147483647, max-stale=2147483647";
media.headers["pragma"] = "cache";
for (var responseHeader in media.headers) {
if (media.headers.hasOwnProperty(responseHeader) && "content-location" != responseHeader) {
res.setHeader(responseHeader, media.headers[responseHeader]);
}
}
// Block further header modification
res.setHeader = function(field, val){};
media.result.pipe(res, {end: true});
//media.result.on("end", function () {
// console.log("attachment#end");
// res.status(200).send(); // have also tried .end() with no luck
//});
},
// Error
function (mediaError) {
console.error("documentClient.readMediaAsync fail->" + JSON.stringify(mediaError));
res.status(400).send(JSON.stringify(mediaError));
}
); ...
显示为 media.result.pipe(...) 的那一行是它被挂断的地方。同样,此代码在移动服务之外工作。我一直在使用 change -> commit -> test -> repeat cycle 但没有任何运气。有人知道如何正确地将流通过管道传输到移动服务中的响应吗?
我成功重现了你的问题,我请求了一段时间后得到了 HTML 代码,但是我在 LOGS 选项卡中也收到了错误消息,它看起来像:
An unhandled exception occurred. Error: Can't set headers after they are sent. at ServerResponse.OutgoingMessage.setHeader (http.js:679:11) at ServerResponse.res.setHeader (D:\home\site\wwwroot\node_modules\express\node_modules\connect\lib\patch.js:59:22) at ServerResponse.res.set.res.header (D:\home\site\wwwroot\node_modules\express\lib\response.js:518:10) at addDefaultHeaders (D:\home\site\wwwroot\runtime\request\requesthandler.js:582:9) at ServerResponse.<anonymous> (D:\home\site\wwwroot\runtime\request\requesthandler.js:291:13) at ServerResponse._.wrap [as end] (D:\home\site\wwwroot\node_modules\underscore\underscore.js:692:22) at onend (stream.js:66:10) at EventEmitter.emit (events.js:126:20) at afterRead (fs.js:1335:12) at Object.wrapper [as oncomplete] (fs.js:367:17)
根据这个日志,我在管道进入响应之前设置了 header,这在我的测试中运行良好。
这是我的简单代码片段:
exports.get = function(request, response) {
var fs = require("fs");
response.setHeader = function(field, val){};
fs.createReadStream('files/123.txt').pipe(response,{end: true});
};
我通过使用节点 documentdb sdk 的非承诺版本解决了这个问题。在响应中一定有什么东西与承诺混淆了(尽管它看起来很简单)。
这是功能代码片段:
clientSync.readMedia(mediaUrl, function (err, mediaStream) {
if (!err && mediaStream) {
mediaStream.headers["cache-control"] = "max-age=2147483647, max-stale=2147483647";
mediaStream.headers["pragma"] = "cache";
for (var responseHeader in mediaStream.headers) {
if (mediaStream.headers.hasOwnProperty(responseHeader) && "content-location" != responseHeader) {
res.setHeader(responseHeader, mediaStream.headers[responseHeader]);
}
}
res.setHeader = function (field, val) {
};
mediaStream.pipe(res);
mediaStream.on('end', function () {
res.status(200).end();
});
} else {
console.error("attachment(" + mediaUrl + ") catch->" + JSON.stringify(err.detail) + "; " + err.message + "; " + err.stack);
res.status(400).send();
}
});
这是我的堆栈:
iOS 和 Android 应用程序
文档数据库
Javascript
支持的移动服务
Javascript
支持的 Azure 站点
我想要做的是从我们的应用程序中提取 DocumentDB 的知识,因为我们正在构建白标签解决方案,我们可能需要 on-the-fly 扩展 DocumentDB 实例。使用抽象类型的服务,我们基本上可以根据从应用程序发送的某些数据来分片我们的 docdb 实例。
现在这将包含 2 个操作,我想为其创建移动服务。一个用于获取 JSON 数据,另一个用于获取与文档关联的附件。这就是我的麻烦所在。我有一个仅用 NodeJS 编写的可部署的 pass-through 服务。我喜欢与移动服务相关的安全模型,所以我想调整我的代码以适应它。问题在于通过管道将 DocDB 响应传递给移动服务响应。首先是移动服务默认值 headers 试图设置但失败了,所以我暂时覆盖了该功能。现在移动服务从不响应,直到发生超时。这是一个代码片段:
exports.get = function (req, res) {
...
// .then().fail() always pushed into the fail() block, but if I use the 2 function in .then() way it works.
client.readMediaAsync(mediaUrl).then(
// Success
function (media) {
// Set up caching and proxy the response
media.headers["cache-control"] = "max-age=2147483647, max-stale=2147483647";
media.headers["pragma"] = "cache";
for (var responseHeader in media.headers) {
if (media.headers.hasOwnProperty(responseHeader) && "content-location" != responseHeader) {
res.setHeader(responseHeader, media.headers[responseHeader]);
}
}
// Block further header modification
res.setHeader = function(field, val){};
media.result.pipe(res, {end: true});
//media.result.on("end", function () {
// console.log("attachment#end");
// res.status(200).send(); // have also tried .end() with no luck
//});
},
// Error
function (mediaError) {
console.error("documentClient.readMediaAsync fail->" + JSON.stringify(mediaError));
res.status(400).send(JSON.stringify(mediaError));
}
); ...
显示为 media.result.pipe(...) 的那一行是它被挂断的地方。同样,此代码在移动服务之外工作。我一直在使用 change -> commit -> test -> repeat cycle 但没有任何运气。有人知道如何正确地将流通过管道传输到移动服务中的响应吗?
我成功重现了你的问题,我请求了一段时间后得到了 HTML 代码,但是我在 LOGS 选项卡中也收到了错误消息,它看起来像:
An unhandled exception occurred. Error: Can't set headers after they are sent. at ServerResponse.OutgoingMessage.setHeader (http.js:679:11) at ServerResponse.res.setHeader (D:\home\site\wwwroot\node_modules\express\node_modules\connect\lib\patch.js:59:22) at ServerResponse.res.set.res.header (D:\home\site\wwwroot\node_modules\express\lib\response.js:518:10) at addDefaultHeaders (D:\home\site\wwwroot\runtime\request\requesthandler.js:582:9) at ServerResponse.<anonymous> (D:\home\site\wwwroot\runtime\request\requesthandler.js:291:13) at ServerResponse._.wrap [as end] (D:\home\site\wwwroot\node_modules\underscore\underscore.js:692:22) at onend (stream.js:66:10) at EventEmitter.emit (events.js:126:20) at afterRead (fs.js:1335:12) at Object.wrapper [as oncomplete] (fs.js:367:17)
根据这个日志,我在管道进入响应之前设置了 header,这在我的测试中运行良好。
这是我的简单代码片段:
exports.get = function(request, response) {
var fs = require("fs");
response.setHeader = function(field, val){};
fs.createReadStream('files/123.txt').pipe(response,{end: true});
};
我通过使用节点 documentdb sdk 的非承诺版本解决了这个问题。在响应中一定有什么东西与承诺混淆了(尽管它看起来很简单)。
这是功能代码片段:
clientSync.readMedia(mediaUrl, function (err, mediaStream) {
if (!err && mediaStream) {
mediaStream.headers["cache-control"] = "max-age=2147483647, max-stale=2147483647";
mediaStream.headers["pragma"] = "cache";
for (var responseHeader in mediaStream.headers) {
if (mediaStream.headers.hasOwnProperty(responseHeader) && "content-location" != responseHeader) {
res.setHeader(responseHeader, mediaStream.headers[responseHeader]);
}
}
res.setHeader = function (field, val) {
};
mediaStream.pipe(res);
mediaStream.on('end', function () {
res.status(200).end();
});
} else {
console.error("attachment(" + mediaUrl + ") catch->" + JSON.stringify(err.detail) + "; " + err.message + "; " + err.stack);
res.status(400).send();
}
});