Problem
每当我们请求列表或查询时,我们都会看到从DocumentDB REST API返回此错误,但是当我们按名称/ id获取对象时,我们看到错误:
输入授权令牌无法提供请求 . 请检查是否按照协议构建了预期的有效负载,并检查所使用的密钥 .
Background
我们已成功将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函数中运行,并且应该尽快执行 .
Code
这是在本地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;
我们在Access control in the DocumentDB API页面中逐字使用了 getAuthorizationTokenFromMasterKey 函数 .
密钥,应用程序名称和用户代理已被x替换为隐私/安全性 .
Test Results
列出数据库
当我尝试对list dbs进行最基本的调用时,服务器返回令牌错误:
var verb = 'GET';
var type = 'dbs';
var link = 'dbs';
响应:
“{\”code \“:\”Unauthorized \“,\”message \“:\”输入授权令牌无法提供请求 . 请检查是否按照协议构建了预期的有效负载,并检查所使用的密钥 . 服务器使用以下有效负载进行签名:'get \ ndbs \ n \ nsat,12 aug 2017 12:28:41 gmt \ n \ n'\ r \ nActivityId:acbf19d9-6485-45c5-9c30-6aa21f14d5b3 \“}”
获取数据库
但是,当我执行get database请求时它工作正常:
var verb = 'GET';
var type = 'dbs';
var link = 'dbs/00001';
响应:
“{\”id \“:\”00001 \“,\”_ rid \“:\”0eUiAA == \“,\”_ ts \“:1441256154,\”_ self \“:\”dbs \ / 0eUiAA = = \ / \ “\ ”_ ETAG \“:\ ”\“ 00007d4a-0000-0000-0000-55e7d2da0000 \ ”\“ \ ”_ colls \“:\ ”colls \ / \“,\” _用户\ “:\” 用户\ / \ “}”
列表集合
同样,从此数据库请求list of collections会返回令牌错误:
var verb = 'GET';
var type = 'colls';
var link = 'dbs/00001/colls';
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';
响应:
“{\”id \“:\”00001 \“,\”indexingPolicy \“:{\”indexingMode \“:\”一致\“,\”自动\“:true,\”includedPaths \“:[{ \ “路径\”:\ “\ / * \”,\ “指数\”:[{\ “之类的\”:\ “范围\”,\ “数据类型\”:\ “号\”,\“精\ “:-1},{\” 样\ “:\” 范围\ “\ ”数据类型\“:\ ”字符串\“,\ ”精密\“: - 1},{\ ”样\“:\”空间\”,\ “数据类型\”:\ “点\”}]}],\ “excludedPaths \”:[]},\ “_ RID \”:\ “0eUiAJMAdQA = \” \ “_ TS \”:1454200014 ,\ “自\”:\ “DBS \ / 0eUiAA == \ / colls \ / 0eUiAJMAdQA = \ / \”,\ “ ETAG \”:\ “\” 00000100-0000-0000-0000-56ad54ce0000 \” \”,\ “_文档\”:\ “文档\ / \”,\ “_存储过程\”:\ “存储过程\ / \”,\ “_触发\”:\ “触发器\ / \”,\ “_的UDF \” :\ “的UDF \ / \”,\ “_冲突\”:\ “矛盾\ / \”}”
列出文件
在该集合上请求list documents给了我这个错误:
var verb = 'GET';
var type = 'docs';
var link = 'dbs/00001/colls/00001/docs';
响应:
“{\”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 \ “}”
获取文件
毫不奇怪,获取single document工作正常:
var verb = 'GET';
var type = 'docs';
var link = 'dbs/00001/colls/00001/docs/e7fe638d-2152-2097-f9c6-9801d7cf5cdd';
响应:
“{\”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}”
查询文件
最后,发送query也会导致令牌错误:
var verb = 'POST';
var type = 'docs';
var link = 'dbs/00001/colls/00001/docs';
var body = `{"query":"SELECT * FROM c", "parameters": []}`;
响应:
“{\”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 \“}”
1 回答
我认为文档不正确 . 他们说
resourceLink
,他们应该说resource id
. 如果您查看Node SDK代码,这就是他们计算授权标头的方式(请注意resourceId
的使用):因此,如果要列出数据库,因为没有资源ID,您需要为
link
变量使用空字符串 . 同样,如果要在数据库中列出集合,则链接实际上应该是数据库的ID(例如dbs/00001
而不是dbs/00001/colls
) .