使用Cloudflare Workers创建动态生成的Sitemap

我的网站使用前后端分离,前端是Vue,后端是Asp.NET core。我正在给我的网站做SEO优化。由于搜索引擎对单页应用支持不好,而我的网站前端又是托管在Cloudflare Pages上,因此很难执行服务端渲染优化。因此我决定使用sitemap来加快搜索引擎收录的速度。

如果你已经使用CMS,请不要使用这种方法生成sitemap。

首先登录Google Search Console,验证网站所有权。验证方式可以选择网域和网址前缀验证。我选择了网址前缀验证。我使用的方法是HTML文件验证。通过上传谷歌提供的文件到网站根目录,完成所有权验证。通过验证后不能移除验证文件,否则所有权验证会过期。

在 控制台>编制索引>站点地图 中可以添加站点地图。

生成sitemap.txt

查询谷歌的文档,发现谷歌支持多种格式的sitemap。我决定首先从简单格式的sitemap开始。

谷歌提供的示例如下

https://www.example.com/file1.html
https://www.example.com/file2.html

为了在Cloudflare Workers中生成这样的文本,我需要从我的API站点中获取已经存在的帖子的数据。我的API站点并不提供帖子的URL信息,因此需要在Worker中执行转换。

转换代码如下:

const mysite = "https://api.example.com/search"
const myblog = "https://example.com/#/blog?id="

  async txt() {
    const url = `${mysite}`

    var data = fetch(url)
      .then((response) => response.json())
      .then((arr) => {
        let sitemap = "";
        for (const obj of arr) {
          sitemap += `${myblog}${obj.id}\n`;
        }
        return sitemap;
      });
    return data;
  },

添加Workers路由

在网站>域名>workers路由 中添加以下项目,以便让worker处理谷歌的爬虫。

/robots.txt
/sitemap*

处理多个任务

我决定将多个任务放入单个worker中,这个worker现在可以生成txt和xml格式的sitemap。

worker.js 代码如下


const bing = ``

const google = ""

export default {
  async fetch(request, env, ctx) {
    const url = new URL(request.url);
    const paths = url.pathname.split('/');

    if (paths.length > 1) {
      switch (paths[1]) {
        case 'BingSiteAuth.xml':
          return new Response(bing, { headers: { "Content-Type": "text/html" } });
        case 'sitemap.txt':
          return generateSitemap.txt()
            .then((map) => { return new Response(map, { headers: { "Content-Type": "text/plain" } }) });
        case 'sitemap.xml':
          return generateSitemap.xml()
            .then((map) => { return new Response(map, { headers: { "Content-Type": "text/xml" } }) });
        case 'robots.txt':
          const robots = `User-agent: *
Allow: /

Sitemap: https://${url.hostname}/sitemap.xml\n`
          return new Response(robots, { headers: { "Content-Type": "text/plain" } });
      }
      if (paths[1] == google) {
        return new Response(`google-site-verification: ${google}`, { headers: { "Content-Type": "text/html" } });
      }
    }
    return new Response('404 not found', { headers: { "Content-Type": "text/html" }, status: 404 });
  },
};

验证

直接用浏览器打开 网站根目录/sitemap.txt 可以看到Worker生成的文本

提交到google search console网站地图,显示发现的网页为n,通过验证。(但这不意味着Google一定会抓取你的网页)

生成XML格式的sitemap

我打算通过直接拼接字符串生成XML,而不使用外部库。

代码如下

  async xml() {
    const url = `${mysite}`

    var data = fetch(url)
      .then((response) => response.json())
      .then((arr) => {
        let sitemap =
          `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
`;
        for (const obj of arr) {
          sitemap +=
            `<url>
<loc>${myblog}${obj.id}</loc>
<lastmod>${obj.createTime}</lastmod>
</url>\n`;
        }
        sitemap += `</urlset>`
        return sitemap;
      });
    return data;
  }

如果接口查询结果已经分页,则需要进行多次查询。

结论

通过Cloudflare Workers实现了动态生成sitemap。好处在于不需要修改源码,更新及时性强。弊端也比较明显,每次请求都要消耗workers请求次数,并且查询会增加后端服务器的负担。