Amazon Services China
亚马逊商城网络服务(亚马逊 MWS)文档

Deprecation Notice:

Amazon Marketplace Web Service (MWS) will no longer be available after March 31, 2024. All MWS developers must migrate to Selling Partner API (SP-API) to avoid service disruptions. Refer to the Migration Hub for more information.

亚马逊 MWS 文档

使用亚马逊 MWS 客户端库

每个亚马逊MWS API 部分都有自己的客户端库,其中所含代码可以帮助您执行许多亚马逊MWS 常见任务。借助亚马逊MWS 客户端库,您可以节省时间,并确认所发送的请求格式正确。例如,亚马逊MWS 客户端库可以为您执行以下任务:

  • 请求签名 - 创建有效的请求 HMAC-SHA 签名。每个请求都必须包含有效的签名,否则请求将被拒绝。请求签名是用您的访问密钥计算出来的,当您注册时分配给您,是只有您和亚马逊MWS 知道的机密信息。
  • 时戳 - 为您提交的每个请求添加时戳。每个请求都必须包含请求的时戳。
  • 请求 - 根据您选择的操作及输入的参数为您构建有效请求。
  • User-Agent 标头 - 创建 User-Agent 标头。
  • 数据流 - 创建数据流,以接收利用 GetReport 操作下载的报告。

创建自己的客户端库

您可以创建自己的客户端库,为您使用亚马逊MWS 提供帮助。您应使用代码按照亚马逊MWS 所要求的格式构建请求,并为其签名,然后解析生成的 XML 响应。

您可以通过以下步骤访问亚马逊MWS

  1. 确定所使用的亚马逊MWS 端点正确无误。
  2. 确定您希望提交操作的相关限制。
  3. 为请求构建查询字符串。
  4. 为查询字符串签名并创建请求。
  5. 向您的亚马逊商城端点发送格式正确的 URL 请求及含有 User-Agent 标头的 HTTP 标头。
  6. 解析响应。

请求格式

亚马逊MWS 支持调用网络服务操作的查询请求。查询请求是简单的 HTTP 请求,使用的是 GET 或 POST 方法,并在 URL 或 HTTP 正文中分别包含查询参数。亚马逊MWS 要求使用 HTTPS,以防止第三方窃听您与亚马逊的沟通信息。

每个 HTTP 标头行必须以回车和换行符结束。查询请求必须包含 Action 参数,以代表需要执行的操作。响应是 XML 格式的文档。

创建规范化查询字符串

要创建亚马逊MWS 查询请求,需先用查询信息构建一个查询字符串。然后为该查询字符串签名,并在提交的请求中包含该字符串。计算签名时,所有参数必须采用自然字节顺序。字符串由下列要素构成:

  • HTTP 操作。该值通常为 POST
  • 请求的域名,例如 https://mws.amazonservices.com/。要获取每个亚马逊商城端点的列表,请参阅本指南的“亚马逊MWS 端点”部分。端点后面是一个正斜杠 (/),它将端点与参数隔开。
  • AWSAccessKeyId — 您的亚马逊MWS 账户是通过访问密钥编码来识别的,亚马逊MWS 利用该编码查找您的访问密钥。
  • Action — 您要对端点执行的操作,如 GetFeedSubmissionResult 操作。
  • Parameters — 所有必需和可选的请求参数。
  • MWSAuthToken — 代表亚马逊卖家对网络应用程序的特定开发商的授权。
  • MarketplaceIdList — 可选的、有结构顺序的商城编号列表,用于支持在多个商城注册的卖家。例如,两个商城编号的格式可能为: &MarketplaceIdList.Id.1=ATVPDKIKX0DER&MarketplaceIdList.Id.2=A1F83G8C2ARO7P。 请注意,MarketplaceIdList 参数不在日本和中国使用。
  • SellerIdMerchant — 您的卖家编号。
  • SignatureMethod — 用于计算签名的 HMAC 哈希算法。HmacSHA256 和 HmacSHA1 都是支持的哈希算法,但亚马逊建议使用 HmacSHA256。
  • SignatureVersion — 当前使用的签名版本。这是亚马逊MWS 特定的信息,它告诉亚马逊MWS 您使用哪种算法来生成构成签名基础的字符串。对于亚马逊MWS,该值目前为 SignatureVersion=2
  • Timestamp — 每个请求都必须包含请求的时戳。根据所用的 API 函数,您可以向请求提供一个过期日期和时间来代替时戳。
  • Version — 所调用的 API 部分的版本。

要创建进行签名的查询字符串,请按照以下步骤操作:

  1. 根据使用自然字节顺序排序的参数名称,对 UTF-8 查询字符串组件进行排序。参数可以来自 GET URI 或 POST 正文(若 Content-Type 编码格式为:application/x-www-form-url)。
  2. 请根据以下原则对参数名称和值进行 URL 编码:
    • 不要对 RFC 3986 定义的任何未保留字符进行 URL 编码。这些未保留的字符包括:A-Z、a-z、0-9、连字符 ( - )、下划线 ( _ )、句点 ( . ) 和取代符号 ( ~ )。
    • 对所有其他字符使用百分号编码 %XY,其中,X 和 Y 分别表示十六进制字符 0-9 和大写 A-F。
    • 以 %XY%ZA... 格式对扩展的 UTF-8 字符进行百分号编码。
    • 以 %20 格式对空格字符进行百分号编码。不要像某些常见编码架构那样,将空格字符百分比编码为 +。
  3. 使用等号 ( = )(ASCII 字符 61)将编码的参数名称与其编码值分隔开(即使参数值为空也是如此)。
  4. 使用 & 号(ASCII 编码 38)将名称/值对 ( & ) 分隔开。
  5. 根据以下伪语法创建要签名的字符串(“n” 表示 ASCII 换行)。
    StringToSign = HTTPVerb + "\n" +
      ValueOfHostHeaderInLowercase + "\n" +
      HTTPRequestURI + "\n" +
      CanonicalizedQueryString <from the preceding step>

    HTTPRequestURI 组件是 URI 到(但不包括)查询字符串的 HTTP 绝对路径组件。如果 HTTPRequestURI 为空,请使用正斜杠 ( / )。

以下示例为 GetFeedSubmissionResult 请求的查询字符串。请注意,排序的参数字符串中不包含空格或换行符。

POST
mws.amazonservices.com
/
AWSAccessKeyId=AKIAFJPPO5KLY6G4XO7Q&Action=GetFeedSubmissionResult&FeedSubm
issionId=4321011681&MWSAuthToken=amzn.mws.4ea38b7b-f563-7709-4bae-87aeaEXAM
PLE&Marketplace=ATVPDKIKX0DER&SellerId=A3F1LGRLCQDI4D&SignatureMethod=HmacS
HA256&SignatureVersion=2&Timestamp=2011-02-04T23%3A08%3A19Z&Version=2009-01
-01

该字符串即为您签名后再包含在查询请求中的字符串。“对查询请求签名”部分介绍了如何对查询请求字符串进行签名。

时戳

在请求中使用的时戳(或过期时间)必须是 dateTime 对象。时戳最好采用国际标准时间(即格林尼治时间)时区格式,例如“2009-03-03T18:12:22Z”或“2009-02-23T18:12:22.093-07:00”。请注意,如果您不在时戳内包含时区信息(“Z”代表 UTC,或者时间差值),亚马逊 MWS 会假设所用时区为 UTC。Timestamp 属性必须包含 ISO8601 格式的客户端机器时间;具有与接收机器时钟明显时间差(15 分钟)的时戳的请求将被拒绝,以防止回放式攻击。有关 XML 格式的时戳的更多信息,请参阅 http://www.w3.org/TR/xmlschema-2/#dateTime

每个亚马逊MWS 响应的 HTTP 响应中均包括一个日期标头,可用于查看本地机器时间是否与我们的服务器时间相同,例如“Date: Tue, 24 Mar 2009 20:34:28 GMT”。您还可以在任意网络浏览器中加载亚马逊MWS 地址 https://mws.amazonservices.com/(无需提交请求),即可获得标有当前亚马逊MWS 服务器时间的响应:

<?xml version="1.0"?>
<PingResponse>
  <Timestamp timestamp="2009-03-24T20:29:19:22Z"/>
</PingResponse>

在使用时戳时,还应注意以下几点:

  • 要允许亚马逊MWS 扩展 PingResponse 的内容,您编写的任何解析 Timestamp 的软件都不应在同层级 XML 标签开始出现时断开。通常,您应根据 http://www.w3.org/TR/webarch/ 中 5.2 部分的网络构建原则,忽略亚马逊MWS 发送给您的 XML 格式的未知标签。
  • 如果您指定一个时戳(而非过期时间),则请求自动在时戳后 15 分钟过期。也就是说,如果请求的时戳早于亚马逊MWS 服务器当前时间 15 分钟或以上,则亚马逊MWS 将不会处理该请求。而且,如果请求的时戳晚于亚马逊MWS 服务器当前时间 15 分钟或以上,则亚马逊MWS 也不会处理该请求。请确保服务器的时间设置正确。
  • 如果您使用的是 .NET,由于对如何降低额外时间精度有不同的解释,因此不可发送太过具体的时戳。为避免使用太过具体的时戳,请手动构建精度不超过毫秒精度的 dateTime 对象。

对查询请求签名

请求签名是验证过程的一部分,旨在识别并验证发送请求的主体。它用作您所构建的请求 URL 中 Signature 参数的值。亚马逊MWS 将验证发送者的身份,以及发送者是否已注册使用 亚马逊MWS。执行验证的方法是利用您的访问密钥编码,来查找用于创建请求签名的密钥。如果验证失败,请求将不予处理。请注意,如果您使用一个亚马逊MWS 客户端库来提交请求,则无需计算签名或时戳。

  1. 请根据上一节“创建规范化查询字符串”中的说明,创建查询请求。以下是查询请求示例:
    POST
    mws.amazonservices.com 
    /
    AWSAccessKeyId=0PExampleR2&Action=SubmitFeed&FeedType=_POST_INVENTORY_AVAIL
    ABILITY_DATA_&MWSAuthToken=amzn.mws.4ea38b7b-f563-7709-4bae-87aeaEXAMPLE&Ma
    rketplace=ATExampleER&SellerId=A1ExampleE6&SignatureMethod=HmacSHA256&Signa
    tureVersion=2&Timestamp=2009-08-20T01%3A10%3A27.607Z&Version=2009-01-01
  2. 利用您刚创建的字符串计算符合 RFC 2104 的 HMAC 值,同时将您的访问密钥当作密钥。HmacSHA256 和 HmacSHA1 都是受支持的哈希算法,但亚马逊建议使用 HmacSHA256。
  3. 将得出的值转换为 base64。
  4. 将得出的值作为 Signature 请求参数的值。

以下示例介绍如何使用 Java 计算签名:

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;

public class SignatureExample {
    private static final String CHARACTER_ENCODING = "UTF-8";
    final static String ALGORITHM = "HmacSHA256";

    public static void main(String[] args) throws Exception {
        // Change this secret key to yours
        String secretKey = "Your secret key";

        // Use the endpoint for your marketplace
        String serviceUrl = "https://mws.amazonservices.com/";

        // Create set of parameters needed and store in a map
        HashMap<String, String> parameters = new HashMap<String,String>();

        // Add required parameters. Change these as needed.
        parameters.put("AWSAccessKeyId", urlEncode("Your Access Key Id"));
        parameters.put("Action", urlEncode("GetFeedSubmissionList"));
        parameters.put("MWSAuthToken", urlEncode("Your MWS Auth Token"));
        parameters.put("SellerId", urlEncode("Your Seller Id"));
        parameters.put("SignatureMethod", urlEncode(ALGORITHM));
        parameters.put("SignatureVersion", urlEncode("2"));
        parameters.put("SubmittedFromDate",
          urlEncode("2013-05-01T12:00:00Z"));
        parameters.put("Timestamp", urlEncode("2013-05-02T16:00:00Z"));
        parameters.put("Version", urlEncode("2009-01-01"));

        // Format the parameters as they will appear in final format
        // (without the signature parameter)
        String formattedParameters = calculateStringToSignV2(parameters,
            serviceUrl);

        String signature = sign(formattedParameters, secretKey);

        // Add signature to the parameters and display final results
        parameters.put("Signature", urlEncode(signature));
        System.out.println(calculateStringToSignV2(parameters,
            serviceUrl));
    }

    /* If Signature Version is 2, string to sign is based on following:
    *
    *    1. The HTTP Request Method followed by an ASCII newline (%0A)
    *
    *    2. The HTTP Host header in the form of lowercase host,
    *       followed by an ASCII newline.
    *
    *    3. The URL encoded HTTP absolute path component of the URI
    *       (up to but not including the query string parameters);
    *       if this is empty use a forward '/'. This parameter is followed
    *       by an ASCII newline.
    *
    *    4. The concatenation of all query string components (names and
    *       values) as UTF-8 characters which are URL encoded as per RFC
    *       3986 (hex characters MUST be uppercase), sorted using
    *       lexicographic byte ordering. Parameter names are separated from
    *       their values by the '=' character (ASCII character 61), even if
    *       the value is empty. Pairs of parameter and values are separated
    *       by the '&' character (ASCII code 38).
    *
    */
    private static String calculateStringToSignV2(
        Map<String, String> parameters, String serviceUrl)
            throws SignatureException, URISyntaxException {
        // Sort the parameters alphabetically by storing
        // in TreeMap structure
        Map<String, String> sorted = new TreeMap<String, String>();
        sorted.putAll(parameters);

        // Set endpoint value
        URI endpoint = new URI(serviceUrl.toLowerCase());

        // Create flattened (String) representation
        StringBuilder data = new StringBuilder();
        data.append("POST\n");
        data.append(endpoint.getHost());
        data.append("\n/");
        data.append("\n");

        Iterator<Entry<String, String>> pairs =
          sorted.entrySet().iterator();
        while (pairs.hasNext()) {
            Map.Entry<String, String> pair = pairs.next();
            if (pair.getValue() != null) {
                data.append( pair.getKey() + "=" + pair.getValue());
            }
            else {
                data.append( pair.getKey() + "=");
            }

            // Delimit parameters with ampersand (&)
            if (pairs.hasNext()) {
                data.append( "&");
            }
        }

        return data.toString();
    }

    /*
     * Sign the text with the given secret key and convert to base64
     */
    private static String sign(String data, String secretKey)
            throws NoSuchAlgorithmException, InvalidKeyException,
                   IllegalStateException, UnsupportedEncodingException {
        Mac mac = Mac.getInstance(ALGORITHM);
        mac.init(new SecretKeySpec(secretKey.getBytes(CHARACTER_ENCODING),
            ALGORITHM));
        byte[] signature = mac.doFinal(data.getBytes(CHARACTER_ENCODING));
        String signatureBase64 = new String(Base64.encodeBase64(signature),
            CHARACTER_ENCODING);
        return new String(signatureBase64);
    }

    private static String urlEncode(String rawValue) {
        String value = (rawValue == null) ? "" : rawValue;
        String encoded = null;

        try {
            encoded = URLEncoder.encode(value, CHARACTER_ENCODING)
                .replace("+", "%20")
                .replace("*", "%2A")
                .replace("%7E","~");
        } catch (UnsupportedEncodingException e) {
            System.err.println("Unknown encoding: " + CHARACTER_ENCODING);
            e.printStackTrace();
        }

        return encoded;
    }
}

创建 User-Agent 标头

User-Agent 标头是可用于标识您的应用程序、其版本号及编程语言。亚马逊建议在提交到亚马逊MWS 的每个请求中都包括 User-Agent 标头,这样可帮助亚马逊更有效地判断和解决问题,也有助于您更好地使用亚马逊MWS

如果您是解决方案提供商,当开发您的应用程序时,在每个请求中都包括 User-Agent 标头非常重要,这也适用于您所开发的桌面应用程序。 这样做的目的是:使亚马逊能够根据卖家使用的解决方案供应商来确定卖家身份,更有效地判断出与您的应用程序相关的问题。

亚马逊MWS 客户端库为在每个亚马逊MWS 请求中传递 User-Agent 标头提供了一种简便方法。当您初始化亚马逊MWS 客户端库时,可以添加应用程序名称或公司名称,以及版本号。其他 HTTP 库也为构建 User-Agent 标头提供了简便方法,但如果您在创建标头时遇到了任何困难,请向亚马逊MWS 寻求帮助。

要创建 User-Agent 标头,请以应用程序名称开头,然后依次是正斜杠、应用程序版本、空格、左括号、Language 名称值对,以及右括号。Language 参数是必需的属性,但您还可以添加其他属性,并以分号隔开。

以下示例展示了在最低限度上可接受的 User-Agent 标头。

AppId/AppVersionId (Language=LanguageNameAndOptionallyVersion)

如果您是第三方应用程序集成商,您可能希望采用类似下面的 User-Agent 标头:

My Desktop Seller Tool/2.0 (Language=Java/1.6.0.11; Platform=Windows/XP)

如果您是通过自己的 IT 部门进行集成的大型卖家,您可能希望采用类似下面的 User-Agent 标头,这样,亚马逊MWS 就能使用 Host 属性帮您解决问题:

MyCompanyName/build1611 (Language=Perl; Host=jane.laptop.example.com)

要指定其他属性,请使用以下格式:AttributeName=Value;,将每个名称值对用分号隔开。如果您想使用反斜杠 (\),请将它连同另一个反斜杠放在括号里 (\\)。同样,在应用程序名称中把一个正斜杠括住 (\/),在应用程序版本中包含一个左括号 (\(),在属性名称中包含一个等号 (\=),在属性值中包含一个右括号 (\)) 和分号 (\;)。

由于 User-Agent 标头要包含在每个请求中进行传送,因此建议您限制标头的长度。如果 User-Agent 标头长度超过 500 个字符,亚马逊MWS 就会拒绝该标头。

创建 URL

URL 包含以下各部分:

  • https://
  • 要访问的商城特定的网络服务端点
  • 规范化查询请求字符串中包含的参数,以及计算出的签名
  • User-Agent 标头

以下示例是您可以提交的完整的请求 URL,实际请求不能包含空格或换行符。

https://mws.amazonservices.com/AWSAccessKeyId=AKIAFJPPO5KLY6G4XO7Q&Action=G
etFeedSubmissionResult&FeedSubmissionId=4321011681&MWSAuthToken=amzn.mws.4e
a38b7b-f563-7709-4bae-87aeaEXAMPLE&Marketplace=ATVPDKIKX0DER&SellerId=A3F1L
GRLCQDI4D&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2011-02-0
4T23%3A08%3A19Z&Version=2009-01-0&Signature=WhateverTheSignatureWas1HTTP/1.
1Host:mws.amazonservices.comX-Amazon-User-Agent:AmazonJavascriptApp/1.0(Lan
guage=Javascript)Content-Type:text/xml