10

尝试使用 rest api 将产品添加到 Magento 时,使用“oauth_problem=nonce_used”消息返回 401 状态。奇怪的是,这些产品仍然是进口的,但这真的让我失望,因为我没有得到产品 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"}]}}

4

5 回答 5

8

在 Mage_Api2_Model_Resource 中,大约第 227 行,找到

$this->getResponse()->setHeader('Location', $newItemLocation);

并在此之后插入:

 $this->getResponse()->setHttpResponseCode(202); 

参考:维基百科“HTTP 位置”:

在两种情况下,HTTP 服务器的响应中会返回 HTTP Location 标头字段:

  1. 要求网络浏览器加载不同的网页。在这种情况下,Location 标头应该与 3xx 的 HTTP 状态代码一起发送。
  2. 提供有关新创建资源的位置的信息。在这种情况下,Location 标头应该使用 201 或 202 的 HTTP 状态码发送
于 2014-05-28T20:38:17.097 回答
1

我遇到了完全相同的问题,并花了数周时间追踪问题。这似乎是 Apache 与 PHP 和 Rewriting 的奇怪组合。最后我创建了一个干净的安装,问题就消失了。我还尝试创建第二个安装,可以观察到问题但失败 - 错误仅出现在我的生产系统中,而不出现在任何测试安装中......

于 2013-10-08T22:39:32.760 回答
1

我查看了这个,从我在代码中看到的内容来看,它看起来像 OAuth 注册了你的所有调用,如果它发现实际上使用了完全相同的随机数,并且时间戳与之前的调用完全相同,它只会丢弃它这个非常具体的 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-timestamp 组合已被使用。

从这个来源:http ://devdocs.magento.com/guides/v2.0/get-started/authentication/gs-authentication-oauth.html

于 2016-04-22T00:04:18.783 回答
0

我遇到了完全相同的问题,为了解决它,我查看了 mod_rewrite apache 模块并打开了该模块的日志记录,这是通过将其添加到您的 apache httpd.conf 文件来完成的(这是针对 apache 2.4x 的,需要 2.2x做的不同

<IfModule mod_rewrite.c>
   LogLevel mod_rewrite.c:trace8
</IfModule>

然后将错误记录到 apache 标准 error_log 当我查看 rewrite here 时,我可以看到我的 post 请求被重写了两次,第一次将产品添加到 magento,第二次再次添加产品失败显然,因为使用了随机数。

我可以看到在 .htaccess 中导致这种情况的重写规则是

## workaround for HTTP authorization
## in CGI environment

  RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 

我检查了我的配置,我确实在运行快速 cgi php,我通过检查 php 信息脚本中的服务器 API 的值来检查这一点。我花了很长时间试图解决这个问题,以至于我知道根本原因我只是将 PHP 从 CGI php 更改为 apache 模块,嘿,现在我的 post 请求只重写一次并返回所有难以捉摸的 200 响应代码。

于 2016-08-11T09:09:45.500 回答
-4

解决方法:

使用 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 的人,但希望它对你们中的一些人有所帮助。我们看到它尝试添加产品两次的错误似乎是特定于服务器配置的,并且很难追踪。

于 2013-04-17T17:40:22.940 回答