非SDK调用Amazon Bedrock签名错误求助及代码示例需求
不使用AWS SDK调用Amazon Bedrock的Node.js/JS实现(修复签名不匹配问题)
问题根源分析
你的代码存在几个关键错误导致签名不匹配:
- Host字段错误:将完整模型路径包含在host中,正确host应为
bedrock-runtime.<region>.amazonaws.com,模型路径属于请求URI - Payload哈希计算错误:直接对JS对象计算哈希,需先序列化为标准JSON字符串再计算
- 哈希与签名未转换为十六进制字符串:crypto-js的加密方法返回对象,需显式转为十六进制格式才能符合AWS签名要求
- Canonical URI设置错误:未包含模型调用的完整路径
修复后的完整代码
import axios from 'axios'; import crypto from 'crypto-js'; async function callBedrock() { // AWS凭证 const accessKey = "YOUR_ACCESS_KEY"; const secretKey = "YOUR_SECRET_KEY"; const method = 'POST'; const service = 'bedrock'; const region = 'eu-central-1'; // 正确的Host:不包含模型路径 const host = `bedrock-runtime.${region}.amazonaws.com`; // 完整的Canonical URI:包含模型调用路径 const canonicalUri = '/model/anthropic.claude-v2:1/invoke'; const baseUrl = `https://${host}`; const contentType = 'application/json'; // 生成AWS要求的日期格式 const amzDate = getAmzDate(new Date().toISOString()); const dateStamp = amzDate.split("T")[0]; // 请求Payload:注意格式符合Claude要求 const payload = { "prompt": "\n\nHuman: Hello how are you\n\nAssistant:", "max_tokens_to_sample": 300, "temperature": 0.5, "top_k": 250, "top_p": 1, "anthropic_version": "bedrock-2023-05-31" }; // 先将Payload序列化为标准JSON字符串,再计算SHA256哈希并转十六进制 const payloadStr = JSON.stringify(payload); const payloadHash = crypto.SHA256(payloadStr).toString(crypto.enc.Hex); // 签名头部:按字母顺序排列(AWS要求) const signedHeaders = 'content-type;host;x-amz-content-sha256;x-amz-date'; // 构建Canonical Headers:确保每个头部小写、值正确,末尾换行 const canonicalHeaders = [ `content-type:${contentType}`, `host:${host}`, `x-amz-content-sha256:${payloadHash}`, `x-amz-date:${amzDate}` ].join('\n') + '\n'; // 构建Canonical Request const canonicalRequest = [ method, canonicalUri, '', // 空的查询字符串 canonicalHeaders, signedHeaders, payloadHash ].join('\n'); // 计算Canonical Request的哈希 const canonicalRequestHash = crypto.SHA256(canonicalRequest).toString(crypto.enc.Hex); // 构建待签名字符串 const algorithm = 'AWS4-HMAC-SHA256'; const credentialScope = `${dateStamp}/${region}/${service}/aws4_request`; const stringToSign = [ algorithm, amzDate, credentialScope, canonicalRequestHash ].join('\n'); // 生成签名密钥 const signingKey = getSignatureKey(secretKey, dateStamp, region, service); // 计算签名并转十六进制 const signature = crypto.HmacSHA256(stringToSign, signingKey).toString(crypto.enc.Hex); // 构建Authorization头部 const authorizationHeader = `${algorithm} Credential=${accessKey}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`; // 请求头部 const headers = { 'Authorization': authorizationHeader, 'Content-Type': contentType, 'X-Amz-Content-Sha256': payloadHash, 'X-Amz-Date': amzDate }; try { const response = await axios({ method: method, baseURL: baseUrl, url: canonicalUri, data: payloadStr, headers: headers }); console.log('Bedrock响应:', response.data); } catch (error) { console.error('请求失败:', error.response?.data || error.message); } } // 生成AWS要求的日期格式(YYYYMMDD'T'HHMMSS'Z') function getAmzDate(dateStr) { let formatted = dateStr.replace(/[:-]/g, ''); formatted = formatted.split('.')[0] + 'Z'; return formatted; } // 生成AWS签名密钥 function getSignatureKey(key, dateStamp, regionName, serviceName) { const kDate = crypto.HmacSHA256(dateStamp, `AWS4${key}`); const kRegion = crypto.HmacSHA256(regionName, kDate); const kService = crypto.HmacSHA256(serviceName, kRegion); const kSigning = crypto.HmacSHA256('aws4_request', kService); return kSigning; } // 调用函数 callBedrock();
关键修改说明
- Host与URI分离:将模型路径从host移到canonicalUri,符合AWS服务的请求结构
- Payload哈希修正:先序列化为JSON字符串再计算哈希,确保和发送的请求体完全一致
- 哈希与签名的字符串转换:所有加密结果都通过
.toString(crypto.enc.Hex)转为十六进制字符串,匹配AWS签名要求 - Canonical Headers构建:用数组拼接保证顺序正确,避免手动拼接的格式错误
- Prompt格式修正:Claude的prompt需要符合
\n\nHuman: ...\n\nAssistant:的格式(原代码里的\n\Utterance是错误的)
内容的提问来源于stack exchange,提问作者Rohana
相关产品推荐
相关产品推荐

