Salesforce Apex调用REST API(OAuth1.0)报400错误求助
核心问题分析
你的代码存在几处关键错误,导致请求格式非法或签名验证失败,这是Postman正常但Apex报错的根本原因:
1. Authorization头格式破坏
拼接OAuth授权头时,oauth_signature_method字段末尾遗漏了逗号,导致后续的oauth_consumer_key字段直接粘连在它后面,完全不符合OAuth头的语法规范:
header+= 'oauth_signature_method="HMAC-SHA1"'; // 此处末尾无逗号,破坏格式 header+= 'oauth_consumer_key="<KEY>", ';
这种错误会让服务器无法解析授权头,直接返回400。
2. OAuth签名密钥计算错误
OAuth 1.0 HMAC-SHA1的签名密钥必须遵循消费者密钥(consumerSecret) + "&" + 令牌密钥(oauth_token_secret)的规则,但你的generateSignature方法仅使用了consumerSecret,完全忽略了token secret:
Blob sig = Crypto.generateMac( 'HmacSHA1', Blob.valueOf(s), Blob.valueOf(consumerSecret) );
这会导致生成的签名与Postman的签名完全不匹配,服务器验证签名失败。
3. Token Secret值前后不一致
在Authorization头中你填写的是oauth_token_secret="<TOKEN>",但在签名计算用的参数Map里却填了parameters.put('oauth_token_secret','<SECRET>'),两者值不统一,进一步导致签名错误。
4. JSON Body未参与签名(若API要求)
你的请求Content-Type为application/json,但当前代码仅在Content-Type是application/x-www-form-urlencoded时,才会将Body参数加入签名基串。如果目标API要求JSON Body也参与签名,这部分逻辑需要调整。
修正后的关键代码片段
针对上述问题,调整后的核心代码如下:
修正Authorization头拼接
String header = 'OAuth '; header+= 'realm="8305111_SB1", '; header+= 'oauth_signature_method="HMAC-SHA1", '; // 补充末尾逗号 header+= 'oauth_consumer_key="<KEY>", '; header+= 'oauth_token="<TOKEN>", '; header+= 'oauth_token_secret="<TOKEN_SECRET>", '; // 统一使用正确的token secret值 header+= 'oauth_version="1.0", '; header+= 'oauth_timestamp="'+timestamp+'", '; header+= 'oauth_nonce="'+nonce+'", ';
修正签名密钥计算
修改generateSignature方法,传入并使用token secret:
// 调用时传入正确的token secret header += 'oauth_signature="'+generateSignature(request, consumerSecret, '<TOKEN_SECRET>', parameters)+'"'; // 修正后的签名生成方法 private static String generateSignature(HttpRequest req, String consumerSecret, String tokenSecret, Map<String,String> parameters) { String s = createBaseString(parameters,req); // 按OAuth规范构建签名密钥 String signingKey = consumerSecret + '&' + tokenSecret; Blob sig = Crypto.generateMac( 'HmacSHA1', Blob.valueOf(s), Blob.valueOf(signingKey) ); return EncodingUtil.urlEncode(EncodingUtil.base64encode(sig), 'UTF-8'); }
统一参数Map中的Token Secret
parameters.put('oauth_token_secret','<TOKEN_SECRET>'); // 与头信息中的值保持一致
额外排查建议
- 开启Postman的请求日志,对比Apex输出的Authorization头、timestamp、nonce、签名值,确保字段格式与Postman完全一致(nonce和timestamp每次请求不同,但格式需统一)。
- 确认请求Endpoint与Postman完全一致,包括Query参数的顺序(OAuth签名对参数顺序敏感)。
- 验证Salesforce生成的
timestamp是UTC时间戳,与Postman使用的时区一致。
内容的提问来源于stack exchange,提问作者Alejandro Ferrante

