Better Late Than Never.

从又拍云搬家到七牛云

为什么要搬

之前一直白嫖又拍云联盟的免费额度,用了挺长时间了。但最近不知道怎么回事,隔三差五就不太稳定,图片加载慢甚至打不开的情况越来越频繁。忍不了了,干脆迁到七牛云算了。

选七牛的理由其实就几个:

  • 国内节点多,访问速度快
  • 有免费额度,小博客够用
  • SDK 文档比较全

开工前要准备的东西

  • rclone 装上(要是还没装去 https://rclone.org/downloads/ 下个 Windows 版就行)
  • 七牛云账号,对象存储 Kodo 开好,先建个桶
  • 又拍云的 S3 密钥和七牛云的密钥都准备好

第一步:配 rclone

找到 rclone.conf 文件,Windows 的话一般在 C:\Users\你的用户名\.config\rclone\rclone.conf,没有就新建一个。

打开贴进去:

[upyun]
type = s3
provider = Other
access_key_id = 又拍云给你的access_key_id
secret_access_key = 又拍云给你的secret_access_key
endpoint = s3.api.upyun.com

[qiniu]
type = s3
provider = Qiniu
access_key_id = 七牛云的access_key
secret_access_key = 七牛云的secret_key
endpoint = s3-cn-east-1.qiniucs.com
region = cn-east-1

又拍云的 access_key_id 和 secret_access_key 要去控制台 → 云产品 → 对象存储 → 对应服务 → S3 API 里找,不是操作员账号密码,别搞混了。

七牛云那边,在控制台 → 密钥管理 里拿 AccessKey/SecretKey。endpoint 看你桶的区域,上面是华南的,华北是 s3-cn-east-1.qiniucs.com,华东是 s3-cn-east-2.qiniucs.com

第二步:试试能不能连上

先跑两条命令看看:

rclone ls upyun:你的桶名字
rclone ls qiniu:你的桶名字

要是都能列出来文件列表,说明配置没问题,继续往下走。

第三步:开搬

直接跑同步命令:

rclone copy upyun:你的桶名字 qiniu:你的桶名字 -P --transfers 8

解释一下几个参数:

  • copy 就是拷贝,目标那边多出来的文件不会删,比较安全
  • -P 显示进度条,不然干等着心慌
  • --transfers 8 同时传 8 个文件,速度拉满

文件多的话建议先 dry-run 一下看看要传多少东西:

rclone copy upyun:你的桶名字 qiniu:你的桶名字 -P --transfers 8 --dry-run

搬完之后检查一下有没有漏的:

rclone check upyun:你的桶名字 qiniu:你的桶名字 --size-only

第四步:旧图片地址怎么办

以前文章里引用的图片地址都是类似 https://xxx.b0.upaiyun.com/images/1.jpg 这种完整路径,不可能一篇篇去改。

我的处理办法是用 Service Worker,在前端拦截图片请求,偷偷把域名换掉。

sw.js 文件

const OLD_DOMAIN = 'xxx.b0.upaiyun.com';
const NEW_DOMAIN = '你的七牛绑定域名.xxx.clouddn.com';

self.addEventListener('fetch', (event) => {
  const url = new URL(event.request.url);

  if (url.hostname === OLD_DOMAIN) {
    url.hostname = NEW_DOMAIN;

    const newRequest = new Request(url, event.request);

    event.respondWith(
      fetch(newRequest).then((response) => {
        const clonedResponse = response.clone();
        caches.open('qiniu-cache').then((cache) => {
          cache.put(newRequest, clonedResponse);
        });
        return response;
      })
    );
  }
});

self.addEventListener('install', () => {
  self.skipWaiting();
});

self.addEventListener('activate', (event) => {
  event.waitUntil(clients.claim());
});

在页面里注册一下

在 HTML 里加一段:

<script>
  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/sw.js');
  }
</script>

这样用户访问页面的时候,图片还是旧的地址,但实际请求会被劫持到七牛云上,用户无感知。

七牛镜像存储(备选)

七牛本身就支持镜像回源功能。如果不想折腾 Service Worker,可以在七牛控制台打开镜像存储,设置回源地址为又拍云。这样用户第一次请求图片时七牛会自动从又拍云拉一份存下来,之后就直接走七牛了。不过这个方案依赖又拍云的源站还活着,既然要迁肯定是想彻底断掉,所以我还是选了 Service Worker。

第五步:后端 PHP 上传

存量文件搬完了,但之后用户上传图片还是要走后端。用七牛官方的 PHP SDK,比手撸签名省事。

先装 SDK:

composer require qiniu/php-sdk

配置放 config/qiniu.php

return [
    'access_key' => env('QINIU_ACCESS_KEY'),
    'secret_key' => env('QINIU_SECRET_KEY'),
    'bucket' => env('QINIU_BUCKET'),
    'domain' => env('QINIU_DOMAIN'), // CDN 加速域名或默认测试域名
];

上传方法:

use Qiniu\Auth;
use Qiniu\Storage\UploadManager;

private static function uploadToQiniu(string $localPath, string $key)
{
    $config = config('qiniu');
    $accessKey = $config['access_key'];
    $secretKey = $config['secret_key'];
    $bucket = $config['bucket'];
    $domain = $config['domain'];

    $auth = new Auth($accessKey, $secretKey);
    $token = $auth->uploadToken($bucket);

    $uploadMgr = new UploadManager();
    list($ret, $err) = $uploadMgr->putFile($token, $key, $localPath);

    if ($err !== null) {
        throw new \Exception($err->message());
    }

    return $domain . '/' . $key;
}

调用:

$url = uploadToQiniu('/tmp/upload.jpg', 'images/2026/07/foo.jpg');

七牛 SDK 会自动处理上传凭证和签名,比手撕 AWS V4 简单多了。

最后

搞完收工,总结一下:

  1. 存量数据用 rclone 迁到七牛,没出啥问题
  2. 旧图片地址用 Service Worker 做了个透明跳转,不用改源码
  3. 新上传的走 PHP SDK 直传七牛
  4. 图片现在走七牛国内节点,速度比又拍云稳

几点提示

  • 七牛免费额度:10GB 存储 + 每月 10GB 流量 + 50 万次 GET 请求,小博客够用
  • Service Worker 需要浏览器支持,太老的 IE 之类就算了
  • 迁移期间如果又拍云那边还有新文件写入,记得再跑一遍 sync 补一下增量
  • 七牛建议绑个自己的 CDN 域名,默认测试域名有时间限制

-- END

写的不错,赞助一下主机费

扫一扫,用支付宝赞赏
扫一扫,用微信赞赏

暂无评论~~