Gra*_*ham 3 azure azure-functions azure-cosmosdb
问题
每当我们请求列表或查询时,我们都会看到从DocumentDB REST API返回此错误,但是当我们按名称/ id获取对象时,我们看到错误:
输入授权令牌无法提供请求.请检查是否按照协议构建了预期的有效负载,并检查所使用的密钥.
背景
我们已成功将node.js sdk与DocumentDB一起使用了一年多,但由于我们希望将后端的restful API代码从node.js App Service迁移到Azure Functions,我们看到10-30秒的滞后时间因为在一段时间内没有调用Function时,DocumentDB sdk加载缓慢.我们知道Function实例很热,并且这不是基于以前与Azure Functions团队通信的冷实例问题.
为了解决这个问题,我们想要测试DocumentDB REST API,它需要零个外部库在node.js函数中运行,并且应该尽快执行.
码
这是在本地node.js中运行的测试工具.一旦它运行,我们将把它移动到Azure功能.
var express = require('express');
var router = express.Router();
var crypto = require("crypto");
var request = require('request');
router.get('/', function (req, res, next) {
var key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
var uri = "https://xxxxxx.documents.azure.com";
var verb = 'GET';
var type = 'dbs';
var link = 'dbs';
var url = `${uri}/${link}`;
var headers = getDefaultRequestHeaders();
// var body = `{"query":"SELECT * FROM c", "parameters": []}`;
var body = '';
headers['content-length'] = body.length;
headers['authorization'] = getAuthorizationTokenUsingMasterKey(verb, type, link, headers['x-ms-date'], key);
request[verb.toLowerCase()]({"url": url, "headers": headers, "body": body}, function (error, response, body) {
// console.log(`error is ${error}`);
// console.log(`response is ${JSON.stringify(response, null, 2)}`);
console.log(`body is ${body}`);
res.status(response.statusCode).json(body);
});
});
function getDefaultRequestHeaders(isQuery, date) {
var headers = {
"content-type": "application/json",
"x-ms-date": new Date().toUTCString(),
"x-ms-version": "2017-02-22",
"accept": "application/json",
"cache-control": "no-cache",
"user-agent": "xxxxxx/1.0"
};
if(isQuery) {
headers["x-ms-documentdb-isquery"] = true;
headers["content-type"] = "application/query+json";
}
if(date) {
headers["x-ms-date"] = date;
}
return headers;
}
function getAuthorizationTokenUsingMasterKey(verb, resourceType, resourceLink, date, masterKey) {
var key = new Buffer(masterKey, "base64");
var text = (verb || "").toLowerCase() + "\n" +
(resourceType || "").toLowerCase() + "\n" +
(resourceLink || "") + "\n" +
date.toLowerCase() + "\n" +
"" + "\n";
var body = new Buffer(text, "utf8");
var signature = crypto.createHmac("sha256", key).update(body).digest("base64");
var MasterToken = "master";
var TokenVersion = "1.0";
return encodeURIComponent("type=" + MasterToken + "&ver=" + TokenVersion + "&sig=" + signature);
}
module.exports = router;
Run Code Online (Sandbox Code Playgroud)
我们从DocumentDB API页面中的Access控件逐字使用getAuthorizationTokenFromMasterKey函数.
密钥,应用程序名称和用户代理已被x替换为隐私/安全性.
检测结果
列出数据库
当我尝试列出dbs的最基本调用时,服务器返回令牌错误:
var verb = 'GET';
var type = 'dbs';
var link = 'dbs';
Run Code Online (Sandbox Code Playgroud)
响应:
"{\"code \":\"Unauthorized \",\"message \":\"输入授权令牌无法提供请求.请检查是否按照协议构建了预期的有效负载,并检查所使用的密钥.服务器使用以下有效负载进行签名:'get \ndbs \n \nsat,12 aug 2017 12:28:41 gmt \n \n'\ r \nActivityId:acbf19d9-6485-45c5-9c30-6aa21f14d5b3 \"}"
获取数据库
但是,当我执行获取数据库请求时它工作正常:
var verb = 'GET';
var type = 'dbs';
var link = 'dbs/00001';
Run Code Online (Sandbox Code Playgroud)
响应:
"{\" ID\":\" 00001\"\ "_摆脱\":\ "0eUiAA == \",\ "_ TS \":1441256154,\ "_自我\":\" DBS\/ 0eUiAA ==\/ \",\ "_ ETAG \":\ "\\" 00007d4a-0000-0000-0000-55e7d2da0000 \\ "\",\ "_ colls \":\ "colls\/ \",\ "_用户\" :\ "用户\/\"}"
列表集合
同样,从此数据库请求集合列表会返回令牌错误:
var verb = 'GET';
var type = 'colls';
var link = 'dbs/00001/colls';
Run Code Online (Sandbox Code Playgroud)
Respose:
"{\"code \":\"Unauthorized \",\"message \":\"输入授权令牌无法提供请求.请检查是否按照协议构建了预期的有效负载,并检查所使用的密钥.服务器使用以下有效负载进行签名:'get \ncolls \ndbs/00001 \nsat,12 Aug 2017 12:32:19 gmt \n \n'\ r \nActivityId:8a9d4ff8-24ef-4fd2-b400-f9f8aa743572 \"} "
获取收藏
但是当我调用get collection时,我得到了一个有效的响应:
var verb = 'GET';
var type = 'colls';
var link = 'dbs/00001/colls/00001';
Run Code Online (Sandbox Code Playgroud)
响应:
"{\" ID\":\" 00001 \",\ "indexingPolicy \":{\ "indexingMode \":\ "一致\"\"自动\":真,\ "includedPaths \":[{\ "路径\":\ "\/*\",\ "指数\":[{\ "之类的\":\ "范围\",\ "数据类型\":\ "号\",\ "精\" :-1},{\ "样\":\ "范围\",\ "数据类型\":\ "字符串\",\ "精密\": - 1},{\ "样\":\"空间\",\ "数据类型\":\ "点\"}]}],\ "excludedPaths \":[]},\ "_ RID \":\ "0eUiAJMAdQA = \"\"_ TS \":1454200014,\"_自\":\ "DBS\/ 0eUiAA ==\/ colls\/ 0eUiAJMAdQA =\/ \",\ "_ ETAG \":\ "\\" 00000100-0000-0000-0000-56ad54ce0000 \\"\ "\"_文档\":\ "文档\/\",\ "_存储过程\":\ "存储过程\/\",\ "_触发\":\ "触发器\/\",\ "_的UDF \":\"的UDF\/ \",\ "_冲突\":\ "矛盾\/\"}"
列出文件
请求该集合上的列表文档给出了这个错误:
var verb = 'GET';
var type = 'docs';
var link = 'dbs/00001/colls/00001/docs';
Run Code Online (Sandbox Code Playgroud)
响应:
"{\"code \":\"Unauthorized \",\"message \":\"输入授权令牌无法提供请求.请检查是否按照协议构建了预期的有效负载,并检查所使用的密钥.服务器使用以下有效负载进行签名:'get \ndocs \ndbs/00001/colls/00001 \nsat,12 aug 2017 12:34:48 gmt \n \n'\ r \nActivityId:57097e95-c41b-4770-b91a- 370418ef2cce\"}"
获取文件
毫不奇怪,获取单个文档可以正常工作:
var verb = 'GET';
var type = 'docs';
var link = 'dbs/00001/colls/00001/docs/e7fe638d-2152-2097-f9c6-9801d7cf5cdd';
Run Code Online (Sandbox Code Playgroud)
响应:
"{\"name \":\"test rest api \",\"id \":\"e7fe638d-2152-2097-f9c6-9801d7cf5cdd \",\"_ rid \":\"0eUiAJMAdQCbHgAAAAAAAA == \",\"_自\":\ "DBS\/ 0eUiAA ==\/ colls\/ 0eUiAJMAdQA =\/文档\/0eUiAJMAdQCbHgAAAAAAAA ==\/ \",\ "_ ETAG \":\ "\\" 0d00d1ee-0000-0000 -0000-598ef7d40000 \\ "\"\"_附件\":\ "附件\/\",\ "_ TS \":1502541779}"
查询文件
最后,发送查询也会导致令牌错误:
var verb = 'POST';
var type = 'docs';
var link = 'dbs/00001/colls/00001/docs';
var body = `{"query":"SELECT * FROM c", "parameters": []}`;
Run Code Online (Sandbox Code Playgroud)
响应:
"{\"code \":\"Unauthorized \",\"message \":\"输入授权令牌无法提供请求.请检查是否按照协议构建了预期的有效负载,并检查所使用的密钥.服务器使用以下有效负载进行签名:'post \ndocs \ndbs/00001/colls/00001 \nsat,12 Aug 2017 12:35:42 gmt \n \n'\ r \nActivityId:b8b95f8c-1339-423e-b0e7- 0d15d3056180\"}"
我认为文档不正确.在他们说的地方resourceLink,他们应该说resource id.如果您查看Node SDK代码,这就是他们计算授权标头的方式(请注意使用resourceId):
getAuthorizationTokenUsingMasterKey: function (verb, resourceId, resourceType, headers, masterKey) {
var key = new Buffer(masterKey, "base64");
var text = (verb || "").toLowerCase() + "\n" +
(resourceType || "").toLowerCase() + "\n" +
(resourceId || "") + "\n" +
(headers["x-ms-date"] || "").toLowerCase() + "\n" +
(headers["date"] || "").toLowerCase() + "\n";
var body = new Buffer(text, "utf8");
var signature = crypto.createHmac("sha256", key).update(body).digest("base64");
var MasterToken = "master";
var TokenVersion = "1.0";
return "type=" + MasterToken + "&ver=" + TokenVersion + "&sig=" + signature;
},
Run Code Online (Sandbox Code Playgroud)
因此,如果要列出数据库,因为没有资源ID,您需要为link变量使用空字符串.同样,如果要在数据库中列出集合,则链接实际上应该是数据库的id(例如dbs/00001,不是dbs/00001/colls).
| 归档时间: |
|
| 查看次数: |
2485 次 |
| 最近记录: |