Ошибки в waNet Принято

3

1. При получении сжатых данных ('Content-Encoding: gzip') результат не распаковывается перед декодированием в json/xml и возникает ошибка.

2. Результат предыдущего запроса обнуляется не вначале следующего запроса, а под конец, поэтому в случае ошибки в необработанном ответе может оказывается результат предыдущего запроса.

3. Результат запроса декодируется до проверки кода по 'expected_http_code', соответственно  вместо исключения о неверном результате запроса получаем исключение о неверном формате данных (выполняется бесполезное декодирование).

4. Не логируются ошибки при декодировании json.

Вот как примерно должно быть:

public function query($url, $content = array(), $method = self::METHOD_GET, $callback = null)
{
    // Reset response
    $this->decoded_response = null;
    $this->raw_response = null;
    $this->response_header = array('http_code' => 500);
    
    $this->buildRequest($url, $content, $method);
    $this->startQuery();
    
    switch ($this->getTransport($url)) {
        case self::TRANSPORT_CURL:
            $this->raw_response = $this->runCurl($url, $content, $method, array(), $callback);
            break;
        case self::TRANSPORT_FOPEN:
            $this->raw_response = $this->runStreamContext($url, $content, $method);
            break;
        case self::TRANSPORT_SOCKET:
            $this->raw_response = $this->runSocketContext($url, $content, $method);
            break;
        default:
            throw new waException('There no suitable network transports', 500);
    }
    
    if ($this->raw_response instanceof self) {
        return $this->raw_response;
    }
    $this->onQueryComplete($this->raw_response);
    return $this->getResponse();
}

protected function onQueryComplete($response)
{
    // @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding
    $encoding = $this->getResponseHeader('Content-Encoding');
    if (in_array($encoding, array('gzip', 'x-gzip')) && function_exists('gzinflate')) {
        // @see http://php.net/manual/ru/function.gzinflate.php#100775
        $response = gzinflate(substr($response, 10, -8));
    }
    
    if ($this->options['expected_http_code'] !== null) {
        if (!is_array($this->options['expected_http_code'])) {
            $this->options['expected_http_code'] = preg_split('@[,:;.\s]+@', $this->options['expected_http_code']);
        }
        $code = $this->getResponseHeader('http_code');
        if (!in_array($code, $this->options['expected_http_code'])) {
            throw new waException($response, $code ? $code : 500);
        }
    }
    
    $this->decodeResponse($response);
}

protected function decodeResponse($response)
{
    switch ($this->options['format']) {
        case self::FORMAT_JSON:
            try {
                $this->decoded_response = waUtils::jsonDecode($response, true);
            } catch (waException $e) {
                $this->log($e->getMessage());
                throw new waException('Error while decode JSON response: '.$e->getMessage(), $e->getCode());
            }
            break;
        case self::FORMAT_XML:
            libxml_clear_errors();
            libxml_use_internal_errors(true);
            libxml_disable_entity_loader(false);
            $xml_options = LIBXML_NOCDATA | LIBXML_NOENT | LIBXML_NONET;
            $this->decoded_response = @simplexml_load_string($response, null, $xml_options);
            if ($this->decoded_response === false) {
                /**
                 * @var LibXMLError $error
                 */
                if ($error = libxml_get_last_error()) {
                    $this->log($error->message);
                    throw new waException('Error while decode XML response: '.$error->message, $error->code);
                }
            }
            break;
        default:
            $this->decoded_response = $response;
    }
}

10 комментариев

  • +1
    Syrnik.com Syrnik.com 27 февраля 2019 13:11 #

    3 пункт спорный

    многие api возвращают ошибку, например авторизации, с сооветствующим кодом и объект ошибки в теле ответа.

    Ну, можно, конечно, поймав исключение, декодировать самостоятельно. Но зачем?

    • +1
      enso_studio@mail.ru enso_studio@mail.ru 27 февраля 2019 14:04 #

      В большинстве случаев ошибки 4хх имеют формат строки или вообще не имеет тела и при попытке их декодировать возникает ошибка. Предложенный вариант таких проблем не имеет, если требуется декодировать ответ для 5хх ошибок которые действительно идут чаще всего в том же формате, то их нужно указать в 'expected_http_code'.

    • +1
      enso_studio@mail.ru enso_studio@mail.ru 5 июля 2019 13:54 #

      а воз поныне там..

    • +1
      Syrnik.com Syrnik.com 11 июля 2019 16:34 #

      5. При вызове multiQuery его $options сохраняются в waNet::$master_options и перекрывают все настройки других запросов в том числе и настройки из конфига net.php. Пример: при вызове расчёта доставки из shopHelper вызывается расчёт всех способов через multiQuery, при этом в опциях вызова жёстко задан таймаут 10с. Таким образом ни настройка "нового" чекаута, ни опции из конфига net.php, ни тем более опция таймаута, устанавливаемая в плагине расчёта доставки никакого влияния не оказывают. Таймаут для всех запросов жёстко фиксируется в 10 сек.

    • +1
      enso_studio@mail.ru enso_studio@mail.ru 11 июля 2019 16:48 #

      при этом в опциях вызова жёстко задан таймаут 10с

      если ты об этом

      waNet::multiQuery(
          'shop.shipping',
          [
              'timeout' => ifset($params, 'timeout', 10),
          ]
      );

      то данное значение берется из настроек магазина, 10с просто значение по умолчанию.

      Хотя я нихрена не понимаю какое это имеет отношение к теме :)

      • +1
        Syrnik.com Syrnik.com 11 июля 2019 16:52 #

        У меня в настройках магазина (чекаута) стоит 60 с. Но передаётся все равно 10

        • +1
          enso_studio@mail.ru enso_studio@mail.ru 11 июля 2019 17:25 #

          поздравляю ты нашел очередной баг WA, хотя учитывая что эта настройка только в оформлении заказа в корзине, то спишут на фичу )

          меня смущает

          while ($active && $mrc == CURLM_OK) {
              if (curl_multi_select(self::$mh[$namespace]) == -1) {
                  usleep(100);
              }
              do {
                  $mrc = curl_multi_exec(self::$mh[$namespace], $active);
              } while ($mrc == CURLM_CALL_MULTI_PERFORM);
          }

          я не разбираюсь в этих мультизапросах, но разве это означает ожидание и по новой?

          • +1
            Syrnik.com Syrnik.com 11 июля 2019 18:13 #

            Настройка от "нового чекаута", похоже, работает только именно в "новом чекауте". Тогда как этот расчёт из shopHelper вызывается ещё много где, например при оформлении через админку. И там только дефолтные 10 сек попадают

          • +1
            enso_studio@mail.ru enso_studio@mail.ru 11 июля 2019 17:35 #

            не 100% - баг т.к. $master_options будет замещать передаваемые значения, причем свойство еще и приватное т.ч. никакого баловства с наследованием

            $this->options = array_merge(
                $this->options,
                $this->getDefaultOptions(),
                $options,
                self::$master_options
            );

            • +1
              Syrnik.com Syrnik.com 11 июля 2019 18:11 #

              Я отнаследовал waNet и перегрузил конструктор

                  public function __construct($options = array(), $custom_headers = array())
                  {
                      parent::__construct($options, $custom_headers);
                      $this->options = array_merge($this->options, $options);
                  }
              

              Добавить комментарий

              Чтобы добавить комментарий, зарегистрируйтесь или войдите