首页
学习
活动
专区
圈层
工具
发布

Amazon Product Advertising API使用Java签署了请求

Amazon Product Advertising API 使用 Java 签署请求指南

基础概念

Amazon Product Advertising API (PA API) 是亚马逊提供的用于访问其产品数据的接口,允许开发者获取产品信息、价格、评论等内容。为了保护API安全,亚马逊要求所有请求必须经过签名验证。

请求签名流程

  1. 创建规范请求 (Canonical Request)
  2. 创建待签字符串 (String to Sign)
  3. 计算签名 (Signature)
  4. 将签名添加到请求头中

Java 实现示例

以下是使用Java签署Amazon Product Advertising API请求的完整示例代码:

代码语言:txt
复制
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

public class AmazonAPISigner {
    
    private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
    private static final String AWS4_HMAC_SHA256 = "AWS4-HMAC-SHA256";
    private static final String ISO8601_FORMAT = "yyyyMMdd'T'HHmmss'Z'";
    private static final String DATE_FORMAT = "yyyyMMdd";
    
    public static void main(String[] args) throws Exception {
        String accessKey = "YOUR_ACCESS_KEY";
        String secretKey = "YOUR_SECRET_KEY";
        String region = "us-west-2";
        String service = "ProductAdvertisingAPI";
        
        // 示例请求参数
        Map<String, String> params = new HashMap<>();
        params.put("Operation", "ItemSearch");
        params.put("Keywords", "Harry Potter");
        params.put("SearchIndex", "Books");
        params.put("ResponseGroup", "Images,ItemAttributes,Offers");
        
        // 生成签名请求
        SignedRequestHelper helper = new SignedRequestHelper(accessKey, secretKey, region, service);
        String url = helper.sign(params);
        
        System.out.println("Signed URL: " + url);
    }
    
    static class SignedRequestHelper {
        private final String accessKey;
        private final String secretKey;
        private final String region;
        private final String service;
        
        public SignedRequestHelper(String accessKey, String secretKey, String region, String service) {
            this.accessKey = accessKey;
            this.secretKey = secretKey;
            this.region = region;
            this.service = service;
        }
        
        public String sign(Map<String, String> params) throws Exception {
            // 添加必要参数
            params.put("Service", service);
            params.put("AWSAccessKeyId", accessKey);
            params.put("Timestamp", timestamp());
            params.put("SignatureVersion", "2");
            params.put("SignatureMethod", "HmacSHA256");
            
            // 对参数进行排序
            TreeMap<String, String> sortedParams = new TreeMap<>(params);
            
            // 创建规范查询字符串
            String canonicalQS = canonicalize(sortedParams);
            
            // 创建待签字符串
            String stringToSign = stringToSign(canonicalQS);
            
            // 计算签名
            String signature = sign(stringToSign, secretKey);
            
            // 将签名添加到查询字符串
            return "http://webservices.amazon.com/onca/xml?" + canonicalQS + "&Signature=" + URLEncoder.encode(signature, StandardCharsets.UTF_8.name());
        }
        
        private String timestamp() {
            SimpleDateFormat df = new SimpleDateFormat(ISO8601_FORMAT);
            df.setTimeZone(TimeZone.getTimeZone("UTC"));
            return df.format(new Date());
        }
        
        private String canonicalize(TreeMap<String, String> sortedParamMap) {
            StringBuilder sb = new StringBuilder();
            for (Map.Entry<String, String> entry : sortedParamMap.entrySet()) {
                if (sb.length() > 0) {
                    sb.append("&");
                }
                sb.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8))
                  .append("=")
                  .append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
            }
            return sb.toString();
        }
        
        private String stringToSign(String canonicalQS) {
            return "GET\nwebservices.amazon.com\n/onca/xml\n" + canonicalQS;
        }
        
        private String sign(String data, String key) throws NoSuchAlgorithmException, InvalidKeyException {
            SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), HMAC_SHA256_ALGORITHM);
            Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
            mac.init(signingKey);
            byte[] rawHmac = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(rawHmac);
        }
    }
}

常见问题及解决方案

1. 签名无效错误

原因

  • 时间戳不正确(与服务器时间相差超过15分钟)
  • 参数未正确排序
  • 编码问题(特殊字符未正确编码)

解决方案

  • 确保使用UTC时间
  • 严格按照字母顺序排序参数
  • 对所有参数名和值进行URL编码

2. 访问被拒绝

原因

  • 访问密钥无效或过期
  • 请求的API端点不正确
  • 未正确设置区域

解决方案

  • 检查并更新AWS凭证
  • 确认使用的是正确的API端点(如webservices.amazon.com)
  • 确保区域设置与API密钥匹配

3. 参数缺失错误

原因

  • 缺少必需参数(如Operation、Timestamp等)
  • 参数拼写错误

解决方案

  • 参考API文档确认所有必需参数
  • 仔细检查参数名称拼写

最佳实践

  1. 密钥管理:不要将密钥硬编码在代码中,使用环境变量或安全存储
  2. 错误处理:实现适当的错误处理和重试机制
  3. 请求限制:遵守API的请求速率限制
  4. 缓存:对频繁请求的数据实施缓存策略
  5. 日志记录:记录请求和响应以便调试

应用场景

  1. 电商价格比较工具
  2. 产品目录管理
  3. 库存监控系统
  4. 个性化推荐引擎
  5. 市场分析工具

通过以上方法和代码示例,您可以成功地在Java中实现Amazon Product Advertising API的请求签名。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

没有搜到相关的文章

领券