![getSignedUrl 给出“SigningError:元数据服务器失败”](https://linux22.com/image/718847/getSignedUrl%20%E7%BB%99%E5%87%BA%E2%80%9CSigningError%EF%BC%9A%E5%85%83%E6%95%B0%E6%8D%AE%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%A4%B1%E8%B4%A5%E2%80%9D.png)
我正在使用带有 HTTP 触发器的 Google Cloud Functions 为 API 调用创建端点。此端点正在使用getSignedUrl
Cloud Storage 包中的函数。我想返回一个签名的 URL,以便客户端可以PUT
访问该 URL 上传文件。
我使用此 API 时遇到不一致的行为。有时我会从该函数返回 URL。然后我尝试更新存储桶名称,但出现此错误:
{ SigningError: Failure from metadata server.
at /user_code/node_modules/@google-cloud/storage/src/file.js:1715:16
at getCredentials (/user_code/node_modules/@google-cloud/storage/node_modules/google-auto-auth/index.js:264:9)
at googleAuthClient.getCredentials (/user_code/node_modules/@google-cloud/storage/node_modules/google-auto-auth/index.js:148:11)
at process._tickDomainCallback (internal/process/next_tick.js:135:7) message: 'Failure from metadata server.' }
如果我将存储桶名称改回来,仍然会看到此错误。我尝试了不同的方法,例如从终端部署。这给了我同样的错误。我也用浏览器创建了该函数,它开始工作。在我尝试更新存储桶名称后,它停止工作了。
通过谷歌搜索,我认为这是一个权限或 ACL 问题,但我不确定如何确认。文档说函数使用<YOUR_PROJECT_ID>@appspot.gserviceaccount.com
服务帐户运行,我可以在函数的常规选项卡中确认这一点。我可以在 IAM 中看到此服务帐户具有Service Account Token Creator
,其中显示:
模拟服务账户(创建 OAuth2 访问令牌、签署 blob 或 JWT 等)。
文档中getSignedUrl
说:
在这些环境中,我们调用 signBlob API 来创建签名 URL。该 API 需要https://www.googleapis.com/auth/iam或者https://www.googleapis.com/auth/cloud-platform范围,因此请确保它们已启用。
我觉得这应该足以让它工作了。我不知道如何明确检查范围。
sign-blob
我尝试过的唯一其他方法是从终端运行。我运行了此命令:
gcloud iam service-accounts sign-blob --iam-account=<my-project-id>@appspot.gserviceaccount.com input.file output.file
我收到此错误:
错误:(gcloud.iam.service-accounts.sign-blob)PERMISSION_DENIED:需要权限 iam.serviceAccounts.signBlob 才能在服务帐户项目/-/serviceAccounts/ 上执行此操作[电子邮件保护]。
我不知道如何检查我的服务帐户是否具有此权限。我尝试在网站上的 IAM、gcloud
终端程序和我的存储桶上设置的权限中查找它。
以下是我的函数代码:
const storage = require('@google-cloud/storage')();
exports.getSignedUrl = (req, res) => {
if(req.method === 'POST') {
// Perform any authorization checks here to assert
// that the end user is authorized to upload.
const myBucket = storage.bucket('my-bucket-name');
const myFile = myBucket.file(req.body.filename);
const contentType = req.body.contentType;
// This link should only last 5 minutes
const expiresAtMs = Date.now() + 300000;
const config = {
action: 'write',
expires: expiresAtMs,
contentType: contentType
};
myFile.getSignedUrl(config, function(err, url) {
if (err) {
console.error(err);
res.status(500).end();
return;
}
res.send(url);
});
} else {
res.status(405).end();
}
}
有人见过这种情况吗?或者知道为什么会发生这种情况吗?或者您知道如何检查我的服务帐户是否具有这些权限或范围吗?我觉得这可能是 GCP 中的一个错误,但很可能是我遗漏了一些东西。我被这个问题困扰了一段时间,如果您能提供任何帮助,我将不胜感激!
答案1
我通过将“云功能服务代理”角色添加到我的“App Engine 默认服务帐户”服务帐户来解决了这个问题。
去:https://console.cloud.google.com/iam-admin/iam
我得到了@rscotten 评论中的屏幕剪辑的指导:https://github.com/googleapis/nodejs-storage/issues/150
答案2
经过反复尝试,我发现该@google-cloud/storage
版本1.6.0
出现了此问题。我降级到1.5.2
并开始正常工作。
我为此开了一个 GitHub 问题:https://github.com/googleapis/nodejs-storage/issues/150