apiKey === null || $this->apiKey === '') { return ''; } // Рендер 2ГИС/Яндекс флакует: иногда возвращается пустой/ошибочный ответ. // Повторяем до $retries раз — берём первый непустой результат. for ($attempt = 1; $attempt <= max(1, $this->retries); $attempt++) { $html = $this->decode($this->request($url)); if ($html !== '') { return $html; } } return ''; } /** * Пачкой (параллельно, порциями по $concurrency). Карта url => html; пустая строка при неудаче. * * @param list $urls * @return array */ public function htmlBatch(array $urls): array { $urls = array_values(array_unique($urls)); if ($this->apiKey === null || $this->apiKey === '' || $urls === []) { return array_fill_keys($urls, ''); } $result = array_fill_keys($urls, ''); foreach (array_chunk($urls, max(1, $this->concurrency)) as $chunk) { $this->fetchChunkInto($chunk, $result); } return $result; } /** * Догружает порцию параллельно, ретраит только оставшиеся пустыми (флак/429) до $retries раз. * * @param list $chunk * @param array $result */ private function fetchChunkInto(array $chunk, array &$result): void { for ($attempt = 1; $attempt <= max(1, $this->retries); $attempt++) { $pending = array_values(array_filter($chunk, fn (string $u): bool => $result[$u] === '')); if ($pending === []) { return; } $responses = Http::pool(fn (Pool $pool) => array_map( fn (string $u) => $pool->as($u)->timeout($this->httpTimeout)->asJson()->post($this->endpoint, [ 'url' => $u, 'api_key' => $this->apiKey, 'render' => $this->render, 'timeout' => $this->renderTimeout, ]), $pending, )); foreach ($pending as $u) { $result[$u] = $this->decode($responses[$u] ?? null); } } } private function request(string $url): Response|\Throwable|null { return Http::timeout($this->httpTimeout)->asJson()->post($this->endpoint, [ 'url' => $url, 'api_key' => $this->apiKey, 'render' => $this->render, 'timeout' => $this->renderTimeout, ]); } private function decode(Response|\Throwable|null $resp): string { if (! $resp instanceof Response || ! $resp->successful()) { return ''; } $b64 = $resp->json('response_body_base64'); if (! is_string($b64) || $b64 === '') { return ''; } $html = base64_decode($b64, true); return is_string($html) ? $html : ''; } }