You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel中生成符合谷歌规范的Gzip压缩Sitemap?

在Laravel中生成符合谷歌规范的Gzip压缩站点地图

下面是满足单文件最多50000条URL、未压缩大小不超50MB要求的具体实现方案:

1. 核心思路

通过分批查询数据生成多个独立的sitemap文件,每个文件控制在50000条URL以内,同时对每个文件进行Gzip压缩;最后生成一个索引文件,统一管理所有子sitemap,方便搜索引擎抓取。

2. 实现步骤

2.1 创建Sitemap生成服务类

编写专门的服务类处理XML构造、分批逻辑和Gzip压缩:

<?php

namespace App\Services;

use Illuminate\Support\Facades\Storage;
use SimpleXMLElement;

class SitemapGenerator
{
    protected $batchSize = 50000; // 单文件最大URL数
    protected $storageDisk = 'public'; // 存储磁盘,可按需修改
    protected $baseUrl;

    public function __construct()
    {
        $this->baseUrl = config('app.url');
    }

    // 生成所有sitemap及索引文件
    public function generate()
    {
        $totalUrls = $this->getTotalUrlCount();
        $totalBatches = ceil($totalUrls / $this->batchSize);

        $sitemapEntries = [];

        for ($batch = 1; $batch <= $totalBatches; $batch++) {
            $fileName = "sitemap-{$batch}.xml.gz";
            $this->generateSingleCompressedSitemap($batch, $fileName);
            $sitemapEntries[] = [
                'loc' => rtrim($this->baseUrl, '/') . "/storage/{$fileName}",
                'lastmod' => now()->toAtomString()
            ];
        }

        $this->generateSitemapIndex($sitemapEntries);
    }

    // 获取需收录的URL总数
    protected function getTotalUrlCount()
    {
        // 替换为你实际的URL来源模型总数,比如文章+商品
        return \App\Models\Post::count() + \App\Models\Product::count();
    }

    // 生成单个Gzip压缩的sitemap文件
    protected function generateSingleCompressedSitemap($batch, $fileName)
    {
        $start = ($batch - 1) * $this->batchSize;
        $urls = $this->getBatchUrls($start, $this->batchSize);

        // 构造XML结构
        $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"/>');
        foreach ($urls as $urlData) {
            $urlNode = $xml->addChild('url');
            $urlNode->addChild('loc', $urlData['loc']);
            $urlNode->addChild('lastmod', $urlData['lastmod']);
            // 可选:添加更新频率和优先级
            // $urlNode->addChild('changefreq', 'weekly');
            // $urlNode->addChild('priority', '0.8');
        }

        // 压缩并存储
        $xmlString = $xml->asXML();
        $compressedContent = gzencode($xmlString, 9); // 最高压缩级别
        Storage::disk($this->storageDisk)->put($fileName, $compressedContent);
    }

    // 获取指定批次的URL数据
    protected function getBatchUrls($start, $limit)
    {
        $urls = [];

        // 分批获取文章URL
        $posts = \App\Models\Post::select('slug', 'updated_at')
            ->skip($start)
            ->take($limit)
            ->get();
        foreach ($posts as $post) {
            $urls[] = [
                'loc' => rtrim($this->baseUrl, '/') . "/posts/{$post->slug}",
                'lastmod' => $post->updated_at->toAtomString()
            ];
        }

        // 若批次还有剩余名额,补充其他模型URL(如商品)
        $remaining = $limit - count($urls);
        if ($remaining > 0) {
            $products = \App\Models\Product::select('slug', 'updated_at')
                ->skip(0) // 需根据实际逻辑调整偏移量,避免重复
                ->take($remaining)
                ->get();
            foreach ($products as $product) {
                $urls[] = [
                    'loc' => rtrim($this->baseUrl, '/') . "/products/{$product->slug}",
                    'lastmod' => $product->updated_at->toAtomString()
                ];
            }
        }

        return $urls;
    }

    // 生成sitemap索引文件
    protected function generateSitemapIndex($entries)
    {
        $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"/>');
        foreach ($entries as $entry) {
            $sitemapNode = $xml->addChild('sitemap');
            $sitemapNode->addChild('loc', $entry['loc']);
            $sitemapNode->addChild('lastmod', $entry['lastmod']);
        }
        Storage::disk($this->storageDisk)->put('sitemap.xml', $xml->asXML());
    }
}

2.2 创建Artisan命令(方便手动/定时生成)

执行命令创建Artisan命令文件:

php artisan make:command GenerateSitemap

修改生成的命令文件:

<?php

namespace App\Console\Commands;

use App\Services\SitemapGenerator;
use Illuminate\Console\Command;

class GenerateSitemap extends Command
{
    protected $signature = 'sitemap:generate';
    protected $description = 'Generate Gzip-compressed sitemaps complying with Google\'s limits';

    public function handle()
    {
        (new SitemapGenerator())->generate();
        $this->info('Sitemaps generated successfully!');
    }
}

2.3 配置存储访问

若使用public磁盘,需创建软链接让文件可通过URL访问:

php artisan storage:link

2.4 定时更新(可选)

若内容频繁更新,在app/Console/Kernel.php中添加定时任务:

protected function schedule(Schedule $schedule)
{
    $schedule->command('sitemap:generate')->daily(); // 每日生成一次
}

3. 关键优化点

  • 大数据量查询优化:若URL总数极大,避免使用skip()+take(),改用基于ID的分段查询(如where('id', '>', $lastId))或游标查询(cursor()),提升性能。
  • 文件大小控制:若单批次50000条URL生成的未压缩XML超过50MB,可适当减小$batchSize(如40000),确保符合谷歌限制。
  • 压缩级别:使用gzencode()最高压缩级别(9),最大化压缩效果,确保文件远小于50MB上限。

内容的提问来源于stack exchange,提问作者Tyler

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 15:11:30