Русский
Русский
English
Статистика
Реклама

Javascript sdk

Интеграция интернет-магазина на 1С-Битрикс с Mindbox

17.07.2020 10:14:14 | Автор: admin
Для развития систем лояльности интернет-магазины обращаются к платформам автоматизации маркетинга, Customer Data Platform (CDP). При этом иногда для успешной интеграции нужно сохранять больше данных, чем указано в документации к API.

Рассказываем, какие данные понадобились нам для интеграции магазина на 1С-Битрикс с платформой Mindbox, как их можно получить с помощью API и SDK и как использовать комбинированный подход с асинхронной отправкой данных.



С помощью сервисов Customer Data Platform ритейлеры узнают портрет своего покупателя, в том числе поведенческие данные. Эта информация хранится в CDP в защищенном виде и помогает ритейлерам в проведении маркетинговых кампаний и аналитике.

Когда покупатель добавляет в корзину телевизор или любой другой товар, CDP сохраняет эти данные. На их основе ритейлеры получают возможность расширить свое взаимодействие с пользователями, например предложить рекомендации и скидки на похожие товары.

Один из наших клиентов сеть магазинов электроники принял решение подключиться к CDP-платформе Mindbox и обратился к нам за помощью в интеграции. Мы проводили интеграцию по ключевым пользовательским сценариям: авторизация, добавление в корзину, оплата и др.

Предыстория


Интернет-магазины могут подключиться к Mindbox двумя основными способами: с помощью API либо JavaScript SDK (об отличиях мы расскажем далее).

Для выбора оптимального способа мы обратились к документации Mindbox, а если информации не хватало, то задавали вопросы менеджеру. Мы выяснили, что наше сотрудничество совпало с периодом бурного роста платформы Mindbox: среднесуточная нагрузка по вызовам API Mindbox увеличилась вдвое (до 120 тысяч запросов в минуту, в пик до 250 тысяч). Это означало, что в период Черной пятницы и прочих распродаж из-за дополнительного роста нагрузки возникал риск, что CDP-сервис окажется недоступен и не получит данные интернет-магазина, который с ним интегрирован.

Mindbox быстро отреагировал на эту проблему и начал улучшать архитектуру и инфраструктуру своих IT-систем, чтобы добиться четырехкратного запаса прочности. Нам, в свою очередь, нужно было обеспечить бесперебойную отправку в Mindbox данных о покупках. Для этого требовалось выбрать самый надежный способ интеграции.

Методы интеграции с Mindbox


Как отмечено выше, Mindbox предлагает использовать для подключения API или JavaScript SDK. Далее рассмотрим их особенности.

  • JavaScript SDK


Библиотека-обёртка над API, предоставляемая сервисом. Её плюсы простота интеграции и возможность асинхронной передачи данных. Оптимально подходит для тех случаев, когда нужно поддерживать только web-платформу.

Ограничения: возможна потеря данных, если Mindbox недоступен в момент отправки. Скрипты платформы не подгрузятся, если на стороне интернет-магазина есть js-ошибки.

  • Интеграция по API


Интеграцию магазина с Mindbox можно провести через API. Этот способ снижает зависимость от JavaScript и также подходит для настройки асинхронной отправки данных.

Ограничения: мы столкнулись с тем, что не получали некоторые данные cookie, а именно уникальный идентификатор пользователя на устройстве (mindboxDeviceUUID). Его необходимо передавать в большинстве операций Mindbox для склеивания информации по пользователю.

В документации эти cookie обязательны не для всех операций. И всё же, стремясь к бесперебойной передаче данных, мы обсудили этот вопрос с менеджером Mindbox. Выяснили, что для максимальной надежности желательно всегда отправлять cookie. При этом для получения cookie нужно использовать JavaScript SDK.

Комбинированный метод


Мы рассмотрели описанные выше способы интеграции, но в чистом виде они не подходили для нашего проекта. Для решения бизнес-задач ритейлера и построения системы лояльности нужно было передавать в Mindbox полный набор данных о действиях пользователей, включая идентификатор из cookie. Одновременно с этим мы стремились снизить зависимость от JavaScript и риски потери данных в случае временной недоступности Mindbox.

Поэтому мы обратились к третьему, комбинированному методу: работаем и с API, и с JavaScript SDK, используя наш модуль очередей.

С помощью Javascript SDK мы идентифицируем пользователя на сайте (mindboxDeviceUUID). Затем на стороне сервера формируем запрос со всеми необходимыми данными и помещаем его в очередь. Запросы из очереди через API отправляются сервису Mindbox. В случае отрицательного ответа запрос повторно помещается в очередь. Таким образом, при отправке данных Mindbox получает полный комплект необходимой информации.

В приведенном далее примере класс Sender позволяет собрать и отправить запрос, выполнив первичную обработку ответа. Класс использует данные из самой команды (тип запроса/ответа, deviceUUID и др.) и из настроек модуля (параметры работы с API, токены и т.п.).

<?phpdeclare(strict_types=1);namespace Simbirsoft\MindBox;use Bitrix\Main\Web\Uri;use Bitrix\Main\Web\HttpClient;use Simbirsoft\Base\Converters\ConverterFactory;use Simbirsoft\MindBox\Contracts\SendableCommand;class Sender{    /** @var Response Тело ответа */    protected $response;    /** @var SendableCommand Команда */    protected $command;    /**     * Sender constructor.     *     * @param SendableCommand $command     */    public function __construct(SendableCommand $command)    {        $this->command = $command;    }    /**     * Сформировать массив заголовков запроса.     *     * @return array     */    protected function getHeaders(): array    {        return [            'Accept'        => Type\ContentType::REQUEST[$this->command->getRequestType()],            'Content-Type'  => Type\ContentType::RESPONSE[$this->command->getResponseType()],            'Authorization' => 'Mindbox secretKey="'. Options::get('secretKey') .'"',            'User-Agent'    => $this->command->getHttpInfo('HTTP_USER_AGENT'),            'X-Customer-IP' => $this->command->getHttpInfo('REMOTE_ADDR'),        ];    }    /**     * Сформировать адрес запроса.     *     * @return string     */    protected function getUrl(): string    {        $uriParts = [            Options::get('apiUrl'),            $this->command->getOperationType(),        ];        $uriParams = [            'operation'  => $this->command->getOperation(),            'endpointId' => Options::get('endpointId'),        ];        $deviceUUID = $this->command->getHttpInfo('deviceUUID');        if (!empty($deviceUUID)) {            $uriParams['deviceUUID'] = $deviceUUID;        }        return (new Uri(implode('/', $uriParts)))            ->addParams($uriParams)            ->getUri();    }    /**     * Отправить запрос.     *     * @return bool     */    public function send(): bool    {        $httpClient = new HttpClient();        $headers = $this->getHeaders();        foreach ($headers as $name => $value) {            $httpClient->setHeader($name, $value, false);        }        $encodedData = null;        $request = $this->command->getRequestData();        if (!empty($request)) {            $converter = ConverterFactory::factory($this->command->getRequestType());            $encodedData = $converter->encode($request);        }        $url = $this->getUrl();        if ($httpClient->query($this->command->getMethod(), $url, $encodedData)) {            $converter = ConverterFactory::factory($this->command->getResponseType());            $response = $converter->decode($httpClient->getResult());            $this->response = new Response($response);            return true;        }        return false;    }    /**     * @return Response     */    public function getResponse(): Response    {        return $this->response;    }}


Трейт Sendable содержит все возможные настройки команды для отправки запроса в Mindbox, в том числе предустановленные, такие как тип запроса/ответа, метод запроса и параметр синхронности/асинхронности. Также в нем присутствуют методы, общие для всех команд.

<?phpdeclare(strict_types=1);namespace Simbirsoft\MindBox\Traits;use RuntimeException;use Bitrix\Main\Context;use Simbirsoft\MindBox\Type;use Simbirsoft\MindBox\Sender;use Simbirsoft\MindBox\Response;use Bitrix\Main\Localization\Loc;use Simbirsoft\MindBox\Contracts\SendableCommand;Loc::loadMessages($_SERVER['DOCUMENT_ROOT'] .'/local/modules/simbirsoft.base/lib/Contracts/Command.php');trait Sendable{    /** @var string Метод отправки (GET/POST) */    protected $method = Type\OperationMethod::POST;    /** @var string Тип операции (sync/async) */    protected $operationType = Type\OperationType::ASYNC;    /** @var string Тип запроса (json/xml) */    protected $requestType = Type\ContentType::JSON;    /** @var string Тип ответа (json/xml) */    protected $responseType = Type\ContentType::JSON;    /** @var array Вспомогательные данные */    protected $data = [];    /**     * Название операции.     * @return string     */    abstract public function getOperation(): string;    /**     * Формируем данные.     *     * @return array     */    abstract public function getRequestData(): array;    /**     * HTTP метод запроса     *     * @return string     */    public function getMethod(): string    {        return $this->method;    }    /**     * Тип операции     *     * @return string     *     * @noinspection PhpUnused     */    public function getOperationType(): string    {        return $this->operationType;    }    /**     * Тип запроса.     *     * @return string     *     * @noinspection PhpUnused     */    public function getRequestType(): string    {        return $this->requestType;    }    /**     * Тип ответа.     *     * @return string     *     * @noinspection PhpUnused     */    public function getResponseType(): string    {        return $this->responseType;    }    /**     * Вспомогательные данные запроса     *     * @return void     */    public function initHttpInfo(): void    {        $server = Context::getCurrent()->getServer();        $request = Context::getCurrent()->getRequest();        $this->data = [            'X-Customer-IP' => $server->get('REMOTE_ADDR'),            'User-Agent'    => $server->get('HTTP_USER_AGENT'),            'deviceUUID'    => $request->getCookieRaw('mindboxDeviceUUID'),        ];    }    /**     * Получить вспомогательные данные запроса     *     * @param string $key     * @param string $default     *     * @return string     *     * @noinspection PhpUnused     */    public function getHttpInfo(string $key, string $default = ''): string    {        return $this->data[$key] ?? $default;    }    /**     * Выполняем команду.     *     * @return void     *     * @throws RuntimeException     */    public function execute(): void    {        /** @var SendableCommand $thisCommand */        $thisCommand = $this;        $sender = new Sender($thisCommand);        if ($sender->send()) {            throw new RuntimeException(Loc::getMessage('BASE_COMMAND_NOT_EXECUTED'));        }        $response = $sender->getResponse();        if (!$response->isSuccess()) {            throw new RuntimeException(Loc::getMessage('BASE_COMMAND_NOT_EXECUTED'));        }        if (!$this->prepareResponse($response)) {            throw new RuntimeException(Loc::getMessage('BASE_COMMAND_NOT_EXECUTED'));        }    }    /**     * Обработка ответа запроса.     *     * @param Response $response     *     * @return bool     */    public function prepareResponse(Response $response): bool    {        // $body   = $response->getBody();        // $status = $body['customer']['processingStatus'];        /**         * Возможные статусы:         * AuthenticationSucceeded - Если пароль верен         * AuthenticationFailed         - Если пароль не верен         * NotFound                          - Если потребитель не найден         */        return true;    }}


В качестве примера рассмотрим событие авторизации пользователя. В обработчике события авторизации мы добавляем в нашу очередь объект класса AuthorizationCommand. В этом классе происходит минимально необходимая подготовка информации, поскольку в момент выполнения команды данные в базе могут измениться, и нужно их сохранить. Также устанавливаются соответствующие параметры для запроса в Mindbox, в данном случае это название операции (узнаем в админ. панели Mindbox). Дополнительно можно указать тип запроса/ответа, метод запроса и параметр синхронности/асинхронности согласно трейту Sendable.

<?phpdeclare(strict_types=1);namespace Simbirsoft\MindBox\Commands;use Simbirsoft\Queue\Traits\Queueable;use Simbirsoft\MindBox\Traits\Sendable;use Simbirsoft\Queue\Contracts\QueueableCommand;use Simbirsoft\MindBox\Contracts\SendableCommand;final class AuthorizationCommand implements QueueableCommand, SendableCommand{    use Queueable, Sendable;    /** @var array Данные пользователя */    protected $user;    /**     * AuthorizationCommand constructor.     *     * @param array $user     */    public function __construct(array $user)    {        $keys = ['ID', 'EMAIL', 'PERSONAL_MOBILE'];        $this->user = array_intersect_key($user, array_flip($keys));        $this->initHttpInfo();    }    /**     * Название операции.     *     * @return string     */    public function getOperation(): string    {        return 'AuthorizationOnWebsite';    }    /**     * Формируем данные.     *     * @return array     */    public function getRequestData(): array    {        return [            'customer' => [                'email' => $this->user['EMAIL'],            ],        ];    }}


Схема взаимодействия модулей


В нашем проекте мы выделили три модуля:

  • Базовый


Служит для хранения общих вспомогательных классов и интерфейсов (например, интерфейсов команд), которые можно потом использовать во всем проекте.

  • Модуль очередей


Взаимодействие с Mindbox реализовано через команды. Для их последовательного выполнения мы используем наш модуль очередей. Этот модуль сохраняет поступившие команды и выполняет их, когда наступает время выполнения.

  • Модуль интеграции с Mindbox


Этот модуль ловит события на сайте, такие, как авторизация, регистрация, создание заказа, добавление в корзину и прочие, а затем формирует команды и отправляет их в модуль очередей.



Модуль Mindbox отслеживает на сайте события и сопутствующую информацию, в том числе из cookie, формирует из них команду и помещает её в очередь. Когда модуль очередей извлекает команду из очереди и выполняет её, происходит отправка данных. Если ответ от Mindbox отрицательный неудачно выполненная команда переносится в конец очереди, если положительный успешно выполненная команда удаляется из очереди.

Таким образом, с помощью описанного выше комбинированного метода мы смогли обеспечить бесперебойную передачу данных в Mindbox.

Подводя итоги


В этой статье мы рассмотрели, какими способами интернет-магазин может подключиться к Customer Data Platform для развития систем лояльности.

В нашем примере в документации Mindbox были описаны два основных способа подключения: через Javascript SDK и через API. Для повышения надежности передачи данных, даже в случае временной недоступности CDP-сервиса, мы выбрали и реализовали третий, комбинированный способ: с помощью API и Javascript SDK, с асинхронной отправкой данных.

Спасибо за внимание! Надеемся, эта статья была для вас полезна.
Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru