尝试使用其余 api 将产品添加到 Magento 时,获取 401 状态并返回“oauth_problem=nonce_used”消息。 奇怪的是,产品仍然被导入,但这真的让我失望,因为我没有得到产品 ID 来更新库存信息。
Magento 安装是全新的(crucialwebhost 安装程序)1.7.0.2,我使用的代码几乎是从 magento 站点复制和粘贴的...
$callbackUrl = '****';
$temporaryCredentialsRequestUrl = "*****/oauth/initiate?oauth_callback=".urlencode($callbackUrl);
$adminAuthorizationUrl = '*****/admin/oauth_authorize';
$accessTokenRequestUrl = '*****/oauth/token';
$apiUrl = '*****/api/rest';
$consumerKey = '*****';
$consumerSecret = '******';
try
{
$authType = ($_SESSION['state'] == 2) ? OAUTH_AUTH_TYPE_AUTHORIZATION : OAUTH_AUTH_TYPE_URI;
$oauthClient = new OAuth($consumerKey, $consumerSecret, OAUTH_SIG_METHOD_HMACSHA1, $authType);
$oauthClient->enableDebug();
if(!isset($_GET['oauth_token']) && !$_SESSION['state'])
{
$requestToken = $oauthClient->getRequestToken($temporaryCredentialsRequestUrl);
$_SESSION['secret'] = $requestToken['oauth_token_secret'];
$_SESSION['state'] = 1;
header('Location: '.$adminAuthorizationUrl.'?oauth_token='.$requestToken['oauth_token']);
exit;
} else if($_SESSION['state'] == 1)
{
$oauthClient->setToken($_GET['oauth_token'], $_SESSION['secret']);
$accessToken = $oauthClient->getAccessToken($accessTokenRequestUrl);
$_SESSION['state'] = 2;
$_SESSION['token'] = $accessToken['oauth_token'];
$_SESSION['secret'] = $accessToken['oauth_token_secret'];
header('Location: '.$callbackUrl);
exit;
} else
{
$oauthClient->setToken($_SESSION['token'], $_SESSION['secret']);
$resourceUrl = "$apiUrl/products";
$productData = json_encode(array(
'type_id' => 'simple',
'attribute_set_id' => 4,
'sku' => $local_product['sku'],
'weight' => 1,
'status' => 1,
'visibility' => 4,
'name' => $local_product['name'],
'description' => $local_product['description'],
'short_description' => $local_product['description'],
'price' => $local_product['price'],
'tax_class_id' => 0,
));
$headers = array('Content-Type' => 'application/json');
$oauthClient->fetch($resourceUrl, $productData, OAUTH_HTTP_METHOD_POST, $headers);
$respHeader = $oauthClient->getLastResponseHeaders();
}
} catch(OAuthException $e)
{
print_r($e);
}
}
session_destroy();
确切错误:{“messages”:{“error”:[{“code”:401,“message”:“oauth_problem=nonce_used”}]}}
在 Mage_Api2_Model_Resource 中,大约第 227 行,找到
$this->getResponse()->setHeader('Location', $newItemLocation);
并在此之后插入:
$this->getResponse()->setHttpResponseCode(202);
参考:维基百科“HTTP 位置”:
HTTP Location 标头字段在 HTTP 的响应中返回 服务器有两种情况:
- 要求网络浏览器加载不同的网页。在这个 在这种情况下,Location 标头应与 HTTP 状态一起发送 代码 3xx。
- 提供有关新地点的信息 创建的资源。在这种情况下,Location 标头应该 使用 HTTP 状态代码 201 或 202 发送
我遇到了完全相同的问题,并花了数周时间来追踪问题。这似乎是 Apache 与 PHP 和 Rewriting 的奇怪组合。最后我创建了一个干净的安装,问题就消失了。我还尝试创建第二个安装,可以观察到问题,但失败了 - 该错误仅出现在我的生产系统中,而不出现在任何测试安装中......
我查看了这个,从代码中看到,看起来 OAuth 注册了您的所有调用,如果它发现完全相同的 nonce 实际上与之前的调用完全相同的 timestamp 一起使用,那么它会因为这个非常具体的 oauth_problem=nonce_used 错误而丢弃它。
代码来自
app/code/core/Mage/Oauth/Model/Server.php
/**
* Validate nonce request data
*
* @param string $nonce Nonce string
* @param string|int $timestamp UNIX Timestamp
*/
protected function _validateNonce($nonce, $timestamp)
{
$timestamp = (int) $timestamp;
if ($timestamp <= 0 || $timestamp > (time() + self::TIME_DEVIATION)) {
$this->_throwException('', self::ERR_TIMESTAMP_REFUSED);
}
/** @var $nonceObj Mage_Oauth_Model_Nonce */
$nonceObj = Mage::getModel('oauth/nonce');
$nonceObj->load($nonce, 'nonce');
if ($nonceObj->getTimestamp() == $timestamp) {
$this->_throwException('', self::ERR_NONCE_USED);
}
$nonceObj->setNonce($nonce)
->setTimestamp($timestamp)
->save();
}
所以我想说,当您在 REST 中通过 Magento API 进行调用时,您应该格外小心,您发出的每个请求都有其自己唯一生成的组合时间戳/随机数值。
另请参阅
oauth_nonce。由应用程序唯一生成的随机值。
oauth_timestamp。一个正整数,以自 1970 年 1 月 1 日 00:00:00 GMT 开始的秒数表示。
还有
nonce_used:nonce-时间戳组合已被使用。
来自此来源:http://devdocs.magento.com/guides/v2.0/get-started/authentication/gs-authentication-oauth.html
我遇到了完全相同的问题,为了解决它,我查看了 mod_rewrite apache 模块并打开了该模块的日志记录,这是通过将其添加到您的 apache httpd.conf 文件中来完成的(这是针对 apache 2.4x 的,2.2x 需要采取不同的做法
<IfModule mod_rewrite.c>
LogLevel mod_rewrite.c:trace8
</IfModule>
然后将错误记录到 apache 标准 error_log 当我查看此处的重写时,我可以看到我的发布请求被重写了两次,第一次将产品添加到 magento,第二次显然由于使用了随机数而未能再次添加产品。
我可以看到 .htaccess 中导致此问题的重写规则就是一个
## workaround for HTTP authorization
## in CGI environment
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
我检查了我的配置,我确实正在运行快速的 cgi php,并且我通过检查 php 信息脚本中的服务器 API 的值来检查这一点。我花了很长时间试图解决这个问题,以至于我知道根本原因,我只是将 PHP 从 CGI php 更改为 apache 模块,嘿,我的帖子请求现在只重写一次,并返回所有难以捉摸的 200 响应代码。
解决方法:
使用 SOAP API。
之前没有使用过的原因:
SOAP API 不提供自定义产品属性或产品数量增量字段的功能。
修复:
使用 SOAP API 将您想要的任何字段添加到产品中,首先为它们创建一个对象数组,如下所示(对于添加的每个字段重复下面的最后 4 行代码):
$additionalAttrs = array();
$per_item = new stdClass();
$per_item->key = 'price_per_item';
$per_item->value = $local_product['price'];
$additionalAttrs['single_data'][] = $per_item;
然后使用键“additional_attributes”将其添加到您的产品数组中,例如:
'additional_attributes' => $additionalAttrs,
我知道这种解决办法只能帮助那些因与我相同的原因而避免使用 SOAP API 的人,但希望它能对你们中的一些人有所帮助。 我们看到它两次尝试添加产品的错误似乎是特定于服务器配置的并且很难追踪。