@jekahm

Почему метод VK API возвращает пустой результат в процессе асинхронного GET запроса?

Доброго времени суток!
Разрабатываю на Yii2 небольшое приложение для поиска юзеров в сообществах с использование VK API. Выборка занимает большое кол-во времени, поэтому изначально показываю пользователю результаты выборки одного сообщетсва и запускаю в фоне скрипт с помощью асинхронного GET запроса.
Но в итоге получаю пустой результат.

Метод, отвечающий за формирование асинхронного запроса:
private function curlRequestAsync($url, $params, $type = 'POST')
	{
		if (is_array($params)) {
			foreach ($params as $key => &$val) {
				if (is_array($val)) $val = implode(',', $val);
				$post_params[] = $key.'='.urlencode($val);
			}
			$post_string = implode('&', $post_params);
		} else {
			$post_string = $params;
		}

		$parts = parse_url($url);

		$fp = fsockopen($parts['host'],
			isset($parts['port'])?$parts['port']:80,
			$errno, $errstr, 30);

		// Data goes in the path for a GET request
		if('GET' == $type) {
			$parts['path'] .= (!empty($post_string)) ? '?' . $post_string . '&user_id=' . Yii::$app->user->identity->id : '';
		}

		$out = "$type ".$parts['path']." HTTP/1.1\r\n";
		$out.= "Host: ".$parts['host']."\r\n";
		$out.= "Content-Type: application/x-www-form-urlencoded\r\n";
		$out.= "Content-Length: ".((!empty($post_string)) ? strlen($post_string) : '1000')."\r\n";
		$out.= "Connection: Close\r\n\r\n";
		// Data goes in the request body for a POST request
		if ('POST' == $type && isset($post_string)) {
			$out.= $post_string;
		}

		fwrite($fp, $out);
		var_dump($out);
		fclose($fp);
	}


Вызов метода:
$this->curlRequestAsync(Url::toRoute(['get-all-members'], true), http_build_query(Yii::$app->request->get()), 'GET');


Часть экшна, в котором происходит фоновый процесс выборки остальных результатов (а именно списка сообщества):
public function actionGetAllMembers() {
		set_time_limit(0);
		ignore_user_abort(true);

		$model = new SearchForm();

		$groups = $model->getUserSubscriptionsNew();

...
	}


Ну и часть самого метода модели для осуществления выборки, используя метод VK API:
public function getUserSubscriptionsNew() {
		$vk = \Yii::$app->authClientCollection->getClient('vkontakte');
		$groups = $vk->post('users.getSubscriptions', ['extended' => 1, 'fields' => 'members_count'])['response'];
		return $groups;
	}


Каким образом можно справиться с данной проблемой?
Заранее благодарен всем за помощь!
  • Вопрос задан
  • 1227 просмотров
Решения вопроса 1
@jekahm Автор вопроса
Решил данную проблему. Может кому пригодится. Само собой, используя функционал Yii2, но общий принцип, думаю, везде один и тот же.
Создаём дополнительное поле в таблице юзеров для хранения токена. При авторизации юзера посредством ВК записываем туда объект OAuthToken (соответственно обаработанный функцией serialize).

serialize($client->getAccessToken())

В экшне actionGetAllMembers дописывем след. код:
$user_id = Yii::$app->request->get('user_id');
$model->refreshSocialToken($user_id);

где user_id - id текущего юзера, который мы передаем данному экшну.
refreshSocialToken - метод модели SearchForm:
public function refreshSocialToken($user_id) {
		$vk = \Yii::$app->authClientCollection->getClient('vkontakte');
		$user = Auth::findOne(['user_id' => $user_id]);
		$vk->setAccessToken(unserialize($user->token));
		return true;
	}

в котором мы извлекаем значения поля token для текущего юзера, куда перед этим был записан сериализованный объект, проводим обратную процедуру unserialize и вызываем метод setAccessToken, чтобы по сути установить еще раз то же самое значения токена.

Делается это всё потому, что при асинхронном запросе сессия, основанная на файлах, блокируется. И значения необходимо установить по новой в текущем экшне (actionGetAllMembers). Что и достигается с помощью метода setAccessToken.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
DmitryVoronkov
@DmitryVoronkov
Python Developer
Я уже писал тебе, про фоновые задачи. в другом вопросе (gearman). Почему ты решил что у тебя метод асинхронный?
Есть еще решение, если лень с очередями задач разбираться ,сделай ,крон, который будет обращаться в базу, раз в 10 секунд например. Складывай запрос пользователя в базу, пусть его дергает крон и получает данные. Пользователь у тебя в любом случае будет ждать.
Есть еще вариант, но он опять с очередями. Складываешь запросы в очередь и результат возвращаешь результат в комет сервер на какой-нибудь канал, этот канал слушает пользователь и по мере решения задач, данные на странице будут обновлятся.
Попробую наглядно:
Пользователь -запрос-> Сервер
Сервер -Часть ответа сразу-> Пользователь
Сервер -Сложная часть->Можно в очередь, можно в консольное приложение
Обработка -Какая-то часть-> Комет сервер (канал)
Пользователь (слушает канал) <-Обновляет данные - Комет сервер
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы