这篇文章诞生的原因是本站主题使用的默认字体APIcdn4.tianli0.top失效了,所以我决定自己反代Google fonts API。为什么说这篇教程没什么用呢?因为我事先不知道Google fonts API可以在大陆直接访问,而且Cloudflare Worker本身在大陆的访问性也不是很好,所以这篇教程大家就当是看着玩吧(◉3◉)

大致步骤

  • 提前注册一个域名并放到Cloudflare上。
  • 创建一个Worker。
  • 配置Worker路由。
  • 部署代码。

创建Worker

  • 点击Workers 和 Pages
  • 点击右上角创建
  • 再点击创建 Worker
  • 输入你喜欢的名字(例如fonts),点击右下角部署
点击右上角创建
点击创建 Worker
输入你喜欢的名字,点击右下角部署

配置Worker路由

  • 点击你添加的域名。
  • 点击Workers 路由
  • 点击添加路由
  • 输入路由,选择Worker,点击保存
  • 复制刚刚创建的Worker URL,并添加一个跟路由一样的DNS记录。
点击添加路由
输入路由(比如fonts.yourdomain.com就输入fonts.yourdomain.com/*),选择Worker,点击保存
复制刚刚创建的Worker URL,并添加一个跟路由一样的DNS记录,代理状态必须为已代理

部署代码

  • 打开刚刚创建的Worker
  • 点击右上角编辑代码
  • 粘贴并编辑代码。
  • 点击右上角部署
点击右上角编辑代码

粘贴并编辑以下代码

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const url = new URL(request.url)

  // 设置 CORS 头部
  const corsHeaders = {
    'Access-Control-Allow-Origin': '*',
    'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
    'Access-Control-Allow-Headers': '*'
  }

  // 处理预检请求 (OPTIONS)
  if (request.method === 'OPTIONS') {
    return new Response(null, {
      status: 204,
      headers: corsHeaders
    })
  }

  // 判断请求路径是否以 /fonts 开头
  if (url.pathname.startsWith('/fonts')) {
    // 构建目标 URL
    const targetUrl = 'https://fonts.googleapis.com' + url.pathname.replace('/fonts', '') + url.search

    // 创建新的请求对象
    const modifiedRequest = new Request(targetUrl, {
      method: request.method,
      headers: request.headers,
      body: request.method === 'POST' ? await request.text() : null
    })

    try {
      // 转发请求
      const response = await fetch(modifiedRequest)
      
      // 获取响应的内容类型
      const contentType = response.headers.get('content-type') || ''
      
      if (contentType.includes('text/') || contentType.includes('application/json')) {
        // 对于文本内容,使用 text() 方法
        const responseText = await response.text()
        
        // 替换所有字体 URL
        const modifiedText = responseText.replace(/https:\/\/fonts\.gstatic\.com/g, 'https://yourdomain.com/gstatic')
        
        // 返回修改后的文本响应
        return new Response(modifiedText, {
          status: response.status,
          statusText: response.statusText,
          headers: {
            ...response.headers,
            'Content-Type': contentType, // 保持原始 Content-Type
            ...corsHeaders
          }
        })
      } else {
        // 对于非文本内容,直接返回原始二进制数据
        const responseArrayBuffer = await response.arrayBuffer()
        
        // 直接返回原始响应体
        return new Response(responseArrayBuffer, {
          status: response.status,
          statusText: response.statusText,
          headers: {
            ...response.headers,
            ...corsHeaders
          }
        })
      }
    } catch (err) {
      return new Response('Error fetching the resource.', {
        status: 500,
        headers: corsHeaders
      })
    }
  }

  // 判断请求是否到达 /gstatic
  else if (url.hostname === 'yourdomain.com' && url.pathname.startsWith('/gstatic')) {
    // 构建目标 URL
    const targetUrl = 'https://fonts.gstatic.com' + url.pathname.replace('/gstatic', '') + url.search

    // 创建新的请求对象
    const modifiedRequest = new Request(targetUrl, {
      method: request.method,
      headers: request.headers,
      body: request.method === 'POST' ? await request.text() : null
    })

    try {
      // 转发请求
      const response = await fetch(modifiedRequest)

      // 直接返回响应体
      return new Response(response.body, {
        status: response.status,
        statusText: response.statusText,
        headers: {
          ...response.headers,
          ...corsHeaders
        }
      })
    } catch (err) {
      return new Response('Error fetching the resource.', {
        status: 500,
        headers: corsHeaders
      })
    }
  }

  // 返回 404 错误
  else {
    return new Response('Not Found', {
      status: 404,
      headers: corsHeaders
    })
  }
}

将上面所有的yourdomain.com更换成你刚刚设置的路由域名。

点击右上角部署

结尾

完成之后就可以访问了,就像下面这样。

https://fonts.yourdomain.com/fonts/css2?family=ZCOOL+KuaiLe