You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js实现HMAC认证接口时返回401 Unauthorised错误如何解决

HMAC API 401错误问题排查

核心错误点(直接导致401)

  • 请求头字段名大小写错误:Node.js的http.request配置项中,请求头的字段名是小写的headers,你的代码写成了大写的Headers,导致Authorization、Date等认证相关请求头都没有被正常发送,服务端拿不到认证信息直接返回401。
  • 请求体前后不一致:生成表征字符串时传入的body是原始的RequestContent,但实际发送请求时你额外做了JSON.stringify(RequestContent)处理,两者内容完全不同,对应的Base64编码不一致,服务端校验签名直接失败。
  • Date头生成时机错误:requestDt是在模块初始化时生成的固定值,若接口调用时间和模块加载时间差超过服务端允许的时间偏移(通常为1~5分钟),会被判定为非法请求返回401,应该每次请求时重新生成当前UTC时间。
  • 缺失utf8模块引入:代码里直接调用utf8.encode(body),但Node.js没有全局utf8对象,若未引入对应依赖会导致表征字符串生成异常,签名计算错误。
  • URI协议不匹配:你代码里_estimateBaseUrl用的是http,如果服务端实际走的是https,生成表征字符串时的完整URI就和服务端接收到的不一致,导致签名校验失败。

其他需要修复的逻辑问题

  • getEstimateID没有封装成Promise,你用await调用时无法正常拿到返回结果,请求成功后的响应也没有正确返回给前端。
  • 生成HMAC签名时没有显式指定utf8编码,部分场景下可能出现编码不一致导致签名错误。

核心代码修正示例

const crypto = require("crypto");
const moment = require('moment');
const https = require('https'); // 服务端是https的话用https模块

let _apiKey = "你的实际API_KEY"; 
let _estimateBaseUrl = "https://estimationapi.zirmed.com/1.0"; // 修正为实际协议
let _estimateTransaction = "/estimate";
let CustomerID = '你的实际CustID'; 
let RequestContent = {}; // 你的实际请求数据对象

getEstimate = async (req, res) => {
  // 每次请求重新生成当前时间
  const requestDt = new Date().toUTCString();
  // 统一处理请求体,避免前后不一致
  const postBody = JSON.stringify(RequestContent);
  try {
    let signature = await createRequestAuth(_estimateTransaction, "POST", requestDt, CustomerID, postBody);
    let response = await getEstimateID(signature, requestDt, postBody);
    res.send(response);
  } catch (err) {
    res.status(500).send(err.message);
  }
};

createRequestAuth = (uriPath, method, requestDate, custId, body = "") => {
  let fullUri = new URL(uriPath, _estimateBaseUrl).toString().toLowerCase();
  let authHashString = CreateAuthHashString(method, fullUri, requestDate, custId, body);
  // 显式指定utf8编码避免编码差异
  let signature = crypto.createHmac('sha256', Buffer.from(_apiKey, 'utf8'))
    .update(authHashString, 'utf8')
    .digest("base64");
  return signature;
}

getEstimateID = (signature, requestDt, postBody) => {
  return new Promise((resolve, reject) => {
    const data = Buffer.from(postBody, 'utf8');
    const options = {
      hostname: 'estimationapi.zirmed.com',
      port: 443, // https对应443,http对应80
      path: '/1.0/estimate',
      method: 'POST',
      // 修正为小写headers
      headers: {
        Authorization: `HMAC ${CustomerID}:${signature}`,
        Date: requestDt,
        "Content-Type": `application/json`,
        'Content-Length': data.length
      }
    }
    const req = https.request(options, res => {
      let result = '';
      res.on('data', d => { result += d })
      res.on('end', () => resolve({statusCode: res.statusCode, data: result}))
    })
    req.on('error', error => reject(error))
    req.write(data)
    req.end()
  })
}

CreateAuthHashString = (method, fullUri, requestDate, custId, body) => {
  // 直接用Buffer处理,不需要额外引入utf8模块
  let content = Buffer.from(body, 'utf8').toString('base64');
  return method + fullUri + moment(requestDate).format('yyyy-MM-DDTHH:mm:ss') + custId + content;
}

module.exports = {
  getEstimate
}

内容的提问来源于stack exchange,提问作者Manoj Patidar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 04:15:03