七牛云如何安全地通过前端上传图片

404 阅读2分钟

在以前的项目中,我通常让前端先将图片上传到自己的服务器,再由服务器将图片转发到七牛云。这种做法虽然控制权完全在后端,但中间多了一次转发,增加了带宽和延迟,也让架构变得复杂。

其实,七牛云官方早已提供了前端直传的方式,不经过自己的服务器也能安全上传。最开始我对此心存疑虑,担心会泄露权限或被滥用。但深入了解之后,我发现这种方式不仅安全可靠,还是官方推荐的最佳实践。

第一步:后端生成上传凭证

前端直传的核心是:前端不能直接拥有七牛云的密钥(Access Key / Secret Key) ,但它可以使用后端生成的「一次性上传凭证」(Upload Token)。

// 需要安装七牛 Node.js SDK:npm install qiniu
import qiniu from 'qiniu';

// 你的七牛云 Access Key 和 Secret Key
const accessKey = '你的AccessKey';
const secretKey = '你的SecretKey';
const bucket = '你的Bucket名称';

// 初始化授权对象
const mac = new qiniu.auth.digest.Mac(accessKey, secretKey);

function generateUploadToken(key: string) {
  const putPolicy = new qiniu.rs.PutPolicy({
    scope: `${bucket}:${key}`, // 限定只能上传到指定 key
    expires: 3600, // Token 有效时间(单位:秒)
    returnBody: JSON.stringify({
      size: "$(fsize)",
      width: "$(imageInfo.width)",
      height: "$(imageInfo.height)",
      mimeType: "$(mimeType)",
    }), // 上传成功后返回的 JSON
    insertOnly: 1, // 只允许插入新文件(防止覆盖)
    mimeLimit: "image/*", // 限制只允许上传图片
    fsizeLimit: 10 * 1024 * 1024, // 文件大小上限为 10MB
  });

  const uploadToken = putPolicy.uploadToken(mac);

  return {
    token: uploadToken,
    key: key, // 返回给前端的文件 key(前端上传时需要)
  };
}

你可以将这个接口部署在后端的 /api/qiniu-token 路由上,前端上传前来获取一次性凭证

第二步:前端使用上传 Token 上传图片

获取 Token 后,前端就可以使用 fetch 或其他方式将文件上传到七牛云的上传地址。

前端上传示例代码

async function uploadToQiniu() {
  const fileInput = document.getElementById('fileInput');
  const file = fileInput?.files?.[0];
  if (!file) {
    alert('请选择文件');
    return;
  }

  // 请求后端上传凭证
  const resp = await fetch('/api/qiniu-token');
  const { token, key } = await resp.json();

  const formData = new FormData();
  formData.append('file', file);
  formData.append('token', token);
  formData.append('key', key); // key 必须和 token 中设置的一致

  // 上传到七牛云,注意选择与你存储区域对应的上传域名
  const uploadResp = await fetch('https://up-z2.qiniup.com/', {
    method: 'POST',
    body: formData,
  });

  if (uploadResp.ok) {
    const result = await uploadResp.json();
    console.log('上传成功:', result);
  } else {
    console.error('上传失败');
  }
}

上传地址 https://up-z2.qiniup.com/ 对应的是华南区域。如果你的空间属于其他区域,请使用对应的上传域名。可参考七牛云的存储区域_产品简介_对象存储 - 七牛开发者中心