$aUrlList * @return bool */ public function pushUrls(array $aUrlList): bool { if (empty($aUrlList)) { return false; } $sIndexNowKey = config('key.indexnow'); $sHostDomain = config('app.site_code', 'clashfreenode.com'); // TEST 时可以写死,但正式环境建议删除这一行 $sHostDomain = 'clashfreenode.com'; if (empty($sIndexNowKey) || empty($sHostDomain)) { Log::error('IndexNow 配置缺失。'); return false; } /** * --------------------------------------------------------- * 1. 清理 URL * --------------------------------------------------------- */ $aUrlList = array_values(array_unique(array_filter( $aUrlList, static function ($sUrl) { return is_string($sUrl) && filter_var($sUrl, FILTER_VALIDATE_URL); } ))); if (empty($aUrlList)) { return false; } /** * --------------------------------------------------------- * 2. 检查 URL 是否真实存在 * --------------------------------------------------------- */ $aValidUrlList = []; foreach ($aUrlList as $sUrl) { // 检查域名 $sUrlHost = parse_url($sUrl, PHP_URL_HOST); if ($sUrlHost !== $sHostDomain) { Log::warning('IndexNow URL 域名不匹配', [ 'url' => $sUrl, 'host' => $sHostDomain, ]); continue; } // 检查页面是否真实存在 if (!$this->urlExists($sUrl)) { Log::warning('IndexNow 跳过不存在的 URL', [ 'url' => $sUrl, ]); continue; } $aValidUrlList[] = $sUrl; } /** * 一个 URL 都不存在 */ if (empty($aValidUrlList)) { Log::warning('IndexNow 没有可推送的有效 URL', [ 'count' => count($aUrlList), ]); return false; } /** * --------------------------------------------------------- * 3. 构造 IndexNow Payload * --------------------------------------------------------- */ $aPayloadData = [ 'host' => $sHostDomain, 'key' => $sIndexNowKey, 'keyLocation' => "https://{$sHostDomain}/{$sIndexNowKey}.txt", 'urlList' => $aValidUrlList, ]; /** * --------------------------------------------------------- * 4. 推送 IndexNow * --------------------------------------------------------- */ try { $oResponse = Http::timeout(10) ->acceptJson() ->withHeaders([ 'Content-Type' => 'application/json; charset=utf-8', ]) ->post( 'https://api.indexnow.org/indexnow', $aPayloadData ); $iStatusCode = $oResponse->status(); /** * 200 = 成功处理 * 202 = 已接受,等待处理 */ if (in_array($iStatusCode, [200, 202], true)) { Log::info('IndexNow 推送成功', [ 'status' => $iStatusCode, 'count' => count($aValidUrlList), 'host' => $sHostDomain, 'urls' => $aValidUrlList, ]); return true; } Log::error('IndexNow 推送失败', [ 'status' => $iStatusCode, 'body' => $oResponse->body(), 'count' => count($aValidUrlList), 'host' => $sHostDomain, 'urls' => $aValidUrlList, ]); return false; } catch (Throwable $e) { Log::error('IndexNow 请求异常', [ 'message' => $e->getMessage(), 'count' => count($aValidUrlList), 'host' => $sHostDomain, ]); return false; } } /** * 判断 URL 页面是否真实存在。 * * 使用 GET 检查,跟搜索引擎实际访问页面的方式更接近。 * * @param string $sUrl * @return bool */ private function urlExists(string $sUrl): bool { try { $oResponse = Http::timeout(10) ->withOptions([ 'allow_redirects' => true, ]) ->get($sUrl); $iStatusCode = $oResponse->status(); Log::info('URL 页面检查', [ 'url' => $sUrl, 'status' => $iStatusCode, ]); /** * 200 ~ 299 * 认为页面正常存在 */ if ($oResponse->successful()) { return true; } Log::warning('URL 页面不存在或无法访问', [ 'url' => $sUrl, 'status' => $iStatusCode, ]); return false; } catch (Throwable $e) { Log::warning('URL 页面检查异常', [ 'url' => $sUrl, 'message' => $e->getMessage(), ]); return false; } } }