利用 Cloudflare Workers 实现 308 重定向

2025 年 02 月 10 日 (已编辑)
1009 字
6 分钟

AI 摘要

奋力赶来...

原来博客中的文章全部保存在 posts 目录之中,利用桌面管理还好,但是在手机中修改就有些混乱了,所以增加了年、月两级目录结构管理。相应的会出现 URL 变化,为了额解决 404 问题,决定利用 Cloudflare Workers 实现一个自动的 308 重定向。

操作步骤

使用 Javascript 实现 Workers 代码,需要维护一个映射关系,满足映射关系的就进行 308 重定向,不满足的就直接访问。

  1. Workers 版本的 308 重定向代码,使用 Map 维护映射关系。
javascript
addEventListener('fetch', (event) => {
  event.respondWith(handleRequest(event.request))
})

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

  // 标准化路径
  path = path.toLowerCase()
  path = path.replace(/\/+/g, '/')

  // 只处理在映射表中的路径并通知搜索引擎
  if (redirectMap.has(path)) {
    const newPath = redirectMap.get(path)
    const newUrl = new URL(newPath, url.origin).toString()

    return new Response(null, {
      status: 308,
      headers: {
        Location: newUrl,
        'Cache-Control': 'public, max-age=31536000',
      },
    })
  }

  // 对于不在映射表中的路径,直接使用原始请求
  return fetch(request.url, {
    method: request.method,
    headers: request.headers,
  })
}

const redirectMap = new Map([
  ['/old-post', '/posts/2024/02/new-post'],
  ['/old-post/', '/posts/2024/02/new-post/'],
  // ... 其他映射
])
  1. 维护最终的 redirectMap,借助 Python 脚本通过新的 posts 目录生成映射结构。
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import json
from pathlib import Path

class RedirectMapGenerator:
    def __init__(self, posts_dir="posts"):
        self.posts_dir = posts_dir
        self.redirect_map = {}

    def scan_posts(self):
        posts_path = Path(self.posts_dir)
        if not posts_path.exists():
            print(f"错误: {self.posts_dir} 目录不存在")
            return

        for md_file in posts_path.rglob("*.md"):
            rel_path = md_file.relative_to(posts_path)
            filename = md_file.stem

            new_url = f"/posts/{str(rel_path.parent / filename)}"
            old_url = f"/posts/{filename}"
            old_url_with_slash = f"/posts/{filename}/"

            new_url = new_url.replace("\\", "/")

            self.redirect_map[old_url] = new_url
            self.redirect_map[old_url_with_slash] = f"{new_url}/"

    def generate_js_map(self):
        """生成JavaScript的Map定义代码"""
        js_entries = []
        for old_url, new_url in self.redirect_map.items():
            js_entries.append(f"  ['{old_url}', '{new_url}']")

        js_code = "const redirectMap = new Map([\n"
        js_code += ",\n".join(js_entries)
        js_code += "\n]);"
        return js_code

    def save_to_file(self, output_file="redirect_map.js"):
        """保存生成的JavaScript代码到文件"""
        js_code = self.generate_js_map()
        with open(output_file, "w", encoding="utf-8") as f:
            f.write(js_code)

    def print_summary(self):
        """打印汇总信息"""
        print(f"\n共生成 {len(self.redirect_map)} 条重定向规则")

def main():
    generator = RedirectMapGenerator()
    generator.scan_posts()
    generator.save_to_file()
    generator.print_summary()

if __name__ == "__main__":
    main()

脚本保存在 posts 同级目录下执行即可得到 redirect_map.js 文件,内容类似:

javascript
const redirectMap = new Map([
  [
    '/posts/setup-mingw64-msys-environment-on-64-bit-windows-7',
    '/posts/2014/02/setup-mingw64-msys-environment-on-64-bit-windows-7',
  ],
  [
    '/posts/setup-mingw64-msys-environment-on-64-bit-windows-7/',
    '/posts/2014/02/setup-mingw64-msys-environment-on-64-bit-windows-7/',
  ],
  ...[
    '/posts/windows-database-backup-ftp-script/',
    '/posts/2020/06/windows-database-backup-ftp-script/',
  ],
])

替换 Workers 中的相应部分即可。

  1. 新建 308 Workers 并使用最终的代码进行部署,并设置路由规则以使 Workers 生效。
设置路由
  1. 开启 Workers 日志,方便查看重定向情况。
Workers日志

测试

直接在终端中使用 curl -I 命令查看相应情况。

使用旧链接进行测试,可以得到 308 重定向。

bash
curl -I https://some.fylsen.com/posts/peng-fu-economic-insights-hsbc-2024/
308重定向

使用新链接测试,会得到 200 响应。

bash
curl -I https://some.fylsen.com/posts/2024/12/peng-fu-economic-insights-hsbc-2024
200响应

为何是 308 而非 301

使用 308 Permanent Redirect 而非 301 Moved Permanently 进行重定向的主要原因在于 HTTP 方法的保持性。具体来说:

  1. 308 保持原始请求方法,而 301 可能更改为 GET

  • 308 Permanent Redirect 强制 客户端在重定向时保持原始的 HTTP 方法(如 POST 仍然是 POST)。

  • 301 Moved Permanently 可能会导致某些客户端(尤其是老版本的浏览器)将 POST 请求转换为 GET,从而改变请求语义,导致数据丢失或功能异常。

  1. 适用场景

  • 如果你希望所有请求(包括 POST、PUT 等)都可以安全地被重定向,并且不改变其请求方法,应使用 308

  • 如果重定向的资源本质上适用于 GET 请求(如页面跳转),或者你可以接受 POST 变成 GET,则 301 仍然是可选的。

  1. SEO 影响

  • 301 和 308 都表示永久重定向,搜索引擎通常会将原 URL 的权重转移到新 URL,因此在 SEO 方面没有太大区别。

总结

  • 使用 308:如果你希望请求方法不变(如 POST、PUT、PATCH 等)。
  • 使用 301:如果你的重定向 URL 适用于 GET,或者你可以接受部分客户端将 POST 变成 GET。

308 适用于 API 迁移、RESTful 服务的永久 URL 变更,而 301 更适合静态网页的永久跳转。

--- ChatGPT

对于静态网页其实效果一样,甚至301更合适,但是为了尝试新东西才选择了 308。

文章标题:利用 Cloudflare Workers 实现 308 重定向

文章作者:Cedar

文章链接:https://fylsen.com/posts/2025/02/implement-308-redirects-with-cloudflare-workers[复制]

最后修改时间:


商业转载请联系站长获得授权,非商业转载请注明本文出处及文章链接,您可以自由地在任何媒体以任何形式复制和分发作品,也可以修改和创作,但是分发衍生作品时必须采用相同的许可协议。
本文采用CC BY-NC-SA 4.0进行许可。