Amazon SP-API Feed上传XML遇SignatureDoesNotMatch错误求助
Amazon SP-API Feeds 上传时 SignatureDoesNotMatch 错误排查
我通过Amazon PHP SP-API SDK及Feeds API官方指南创建并上传Feed XML至AWS,已成功获取url和feedDocumentId,但上传时始终返回SignatureDoesNotMatch错误,错误信息如下:
<Error> <Code>SignatureDoesNotMatch</Code> <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message> <AWSAccessKeyId>AKIAX2ZVOZFBB4YFXXHU</AWSAccessKeyId> <StringToSign>AWS4-HMAC-SHA256 20231106T080142Z 20231106/eu-west-1/s3/aws4_request c2cbc4a511455b617c11d9ea1b41bfd2134b4f7d646b286e7848a9203ef5e13e</StringToSign> <SignatureProvided>e01f1837a5e5cc2d4defae363a83812b2e48c5b4d9c28fcc46f6a96a9a7d24cf</SignatureProvided> <StringToSignBytes>41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 0a 32 30 32 33 31 31 30 36 54 30 38 30 31 34 32 5a 0a 32 30 32 33 31 31 30 36 2f 65 75 2d 77 65 73 74 2d 31 2f 73 33 2f 61 77 73 34 5f 72 65 71 75 65 73 74 0a 63 32 63 62 63 34 61 35 31 31 34 35 35 62 36 31 37 63 31 31 64 39 65 61 31 62 34 31 62 66 64 32 31 33 34 62 34 66 37 64 36 34 36 62 32 38 36 65 37 38 34 38 61 39 32 30 33 65 66 35 65 31 33 65</StringToSignBytes> <CanonicalRequest>GET /dc372987-1dd1-43b3-b516-27dc78dca0ec.amzn1.tortuga.4.eu.TH04D1RNGNQZS X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAX2ZVOZFBB4YFXXHU%2F20231106%2Feu-west-1%2Fs3%2Faws4_request&X-Amz-Date=20231106T080142Z&X-Amz-Expires=300&X-Amz-SignedHeaders=content-type%3Bhost content-type: host:tortuga-prod-eu.s3-eu-west-1.amazonaws.com content-type;host UNSIGNED-PAYLOAD</CanonicalRequest> <CanonicalRequestBytes>47 45 54 0a 2f 64 63 33 37 32 39 38 37 2d 31 64 64 31 2d 34 33 62 33 2d 62 35 31 36 2d 32 37 64 63 37 38 64 63 61 30 65 63 2e 61 6d 7a 6e 31 2e 74 6f 72 74 75 67 61 2e 34 2e 65 75 2e 54 48 30 34 44 31 52 4e 47 4e 51 5a 53 0a 58 2d 41 6d 7a 2d 41 6c 67 6f 72 69 74 68 6d 3d 41 57 53 34 2d 48 4d 41 43 2d 53 48 41 32 35 36 26 58 2d 41 6d 7a 2d 43 72 65 64 65 6e 74 69 61 6c 3d 41 4b 49 41 58 32 5a 56 4f 5a 46 42 42 34 59 46 58 58 48 55 25 32 46 32 30 32 33 31 31 30 36 25 32 46 65 75 2d 77 65 73 74 2d 31 25 32 46 73 33 25 32 46 61 77 73 34 5f 72 65 71 75 65 73 74 26 58 2d 41 6d 7a 2d 44 61 74 65 3d 32 30 32 33 31 31 30 36 54 30 38 30 31 34 32 5a 26 58 2d 41 6d 7a 2d 45 78 70 69 72 65 73 3d 33 30 30 26 58 2d 41 6d 7a 2d 53 69 67 6e 65 64 48 65 61 64 65 72 73 3d 63 6f 6e 74 65 6e 74 2d 74 79 70 65 25 33 42 68 6f 73 74 0a 63 6f 6e 74 65 6e 74 2d 74 79 70 65 3a 0a 68 6f 73 74 3a 74 6f 72 74 75 67 61 2d 70 72 6f 64 2d 65 75 2e 73 33 2d 65 75 2d 77 65 73 74 2d 31 2e 61 6d 61 7a 6f 6e 61 77 73 2e 63 6f 6d 0a 0a 63 6f 6e 74 65 6e 74 2d 74 79 70 65 3b 68 6f 73 74 0a 55 4e 53 49 47 4e 45 44 2d 50 41 59 4c 4f 41 44</CanonicalRequestBytes> <RequestId>EJ9N9STNFFT5FT97</RequestId> <HostId>rVh8aMdyJ3nzfI2vIqgvn0WHCwkfEvZAAMtZ33JY6Bk8OyFNCucBKesfAe3gLyvLjo50ZVsfY223ZyzfEcYp+g==</HostId> </Error>
我的实现代码如下:
public function createFeed($distributionChannelTeamId) { $res=$this->createFeedDocument($distributionChannelTeamId); $url=$res['url']; $feedDocumentId=$res['feedDocumentId']; if($res['url'] && $res['feedDocumentId']){ $requestXml = '<?xml version="1.0" encoding="iso-8859-1"?> <AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amzn-envelope.xsd"> <Header> <DocumentVersion>1.01</DocumentVersion> <MerchantIdentifier>MYID</MerchantIdentifier> </Header> <MessageType>Product</MessageType> <PurgeAndReplace>false</PurgeAndReplace> <Message> <MessageID>1</MessageID> <OperationType>Update</OperationType> <Product> <SKU>56789</SKU> <StandardProductID> <Type>ASIN</Type> <Value>B0EXAMPLEG</Value> </StandardProductID> <ProductTaxCode>A_GEN_NOTAX</ProductTaxCode> <DescriptionData> <Title>Example Product Title</Title> <Brand>Example Product Brand</Brand> <Description>This is an example product description.</Description> <BulletPoint>Example Bullet Point 1</BulletPoint> <BulletPoint>Example Bullet Point 2</BulletPoint> <MSRP currency="USD">25.19</MSRP> <Manufacturer>Example Product Manufacturer</Manufacturer> <ItemType>example-item-type</ItemType> </DescriptionData> <ProductData> <Health> <ProductType> <HealthMisc> <Ingredients>Example Ingredients</Ingredients> <Directions>Example Directions</Directions> </HealthMisc> </ProductType> </Health> </ProductData> </Product> </Message> </AmazonEnvelope>'; $response = Http::withHeaders(['Content-Type' => 'application/xml' ])->put($url,[ 'body' => utf8_encode($requestXml) ]); Log::channel('amazon')->info('Amazon create feed response: ', ['response' => $response]); dd($response); }else{ dump('no res'); dd($res); } }
问题排查与修复方案
1. 请求方法与预签名不匹配
从错误信息的CanonicalRequest中可以看到,签名计算使用的是GET方法,但你的代码中使用了PUT方法。这是核心问题——预签名URL绑定了特定的HTTP方法,必须严格匹配。
2. 请求体传递方式错误
Laravel的Http::put方法第二个参数如果是数组,会被解析为表单参数,而非原始请求体。需要直接传递字符串内容,或者使用withBody方法明确指定原始内容。
3. 编码与Content-Type匹配
如果使用utf8_encode转换XML编码,需要在Content-Type头中添加对应的charset,确保服务器能正确解析内容。
修正后的代码
public function createFeed($distributionChannelTeamId) { $res = $this->createFeedDocument($distributionChannelTeamId); $url = $res['url']; $feedDocumentId = $res['feedDocumentId']; if ($url && $feedDocumentId) { $requestXml = '<?xml version="1.0" encoding="iso-8859-1"?> <AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amzn-envelope.xsd"> <Header> <DocumentVersion>1.01</DocumentVersion> <MerchantIdentifier>MYID</MerchantIdentifier> </Header> <MessageType>Product</MessageType> <PurgeAndReplace>false</PurgeAndReplace> <Message> <MessageID>1</MessageID> <OperationType>Update</OperationType> <Product> <SKU>56789</SKU> <StandardProductID> <Type>ASIN</Type> <Value>B0EXAMPLEG</Value> </StandardProductID> <ProductTaxCode>A_GEN_NOTAX</ProductTaxCode> <DescriptionData> <Title>Example Product Title</Title> <Brand>Example Product Brand</Brand> <Description>This is an example product description.</Description> <BulletPoint>Example Bullet Point 1</BulletPoint> <BulletPoint>Example Bullet Point 2</BulletPoint> <MSRP currency="USD">25.19</MSRP> <Manufacturer>Example Product Manufacturer</Manufacturer> <ItemType>example-item-type</ItemType> </DescriptionData> <ProductData> <Health> <ProductType> <HealthMisc> <Ingredients>Example Ingredients</Ingredients> <Directions>Example Directions</Directions> </HealthMisc> </ProductType> </Health> </ProductData> </Product> </Message> </AmazonEnvelope>'; // 直接传递转换后的XML字符串作为请求体 $response = Http::withHeaders([ 'Content-Type' => 'application/xml; charset=utf-8' ])->put($url, utf8_encode($requestXml)); Log::channel('amazon')->info('Amazon create feed response: ', ['response' => $response]); dd($response); } else { dump('no res'); dd($res); } }
额外排查点
- 确认
createFeedDocument返回的URL确实对应PUT方法,若返回的是GET方法的URL,需检查SDK调用逻辑。 - 检查服务器时间与AWS服务器时间同步,签名对时间敏感,时间差超过5分钟会导致签名失败。
- 不要添加
SignedHeaders之外的额外HTTP头,错误中指定的允许头为content-type;host,请勿添加其他头信息。
内容的提问来源于stack exchange,提问作者Mica
相关产品推荐
相关产品推荐

