阿里云 OSS 教程

学习使用阿里云对象存储服务 (OSS) 实现文件上传、存储和图片处理功能

什么是阿里云 OSS?

阿里云对象存储服务 (OSS) 是一款海量、安全、低成本、高可靠的云存储服务。 它提供了丰富的文件存储和处理功能,特别适合 Web 应用的静态资源存储。

文件上传

支持多种文件格式的上传和存储

图片处理

实时图片缩放、裁剪、水印等处理

CDN 加速

全球内容分发网络,快速访问

OSS 设置和配置

首先需要在阿里云控制台创建 OSS Bucket,获取访问密钥, 然后在 Next.js 项目中配置 OSS 客户端。

lib/oss.ts
// lib/oss.ts
import OSS from 'ali-oss';

// OSS 客户端配置
export const ossClient = new OSS({
  region: process.env.OSS_REGION!, // 例如:'oss-rg-china-mainland'
  accessKeyId: process.env.OSS_ACCESS_KEY_ID!,
  accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET!,
  bucket: process.env.OSS_BUCKET!, // 例如:'next-static-oss'
});

// 获取文件 URL
export function getOSSUrl(filename: string): string {
  return `${process.env.BASE_OSS_URL}/${filename}`;
}

// 生成唯一文件名
export function generateUniqueFilename(originalName: string): string {
  const timestamp = Date.now();
  const random = Math.random().toString(36).substring(2);
  const extension = originalName.split('.').pop();
  return `${timestamp}-${random}.${extension}`;
}

// 文件上传工具类
export class OSSManager {
  // 上传文件
  static async uploadFile(
    file: File | Buffer,
    filename: string,
    options?: {
      folder?: string;
      metadata?: Record<string, string>;
    }
  ): Promise<{ url: string; filename: string }> {
    try {
      const { folder = '', metadata = {} } = options || {};
      const fullPath = folder ? `${folder}/${filename}` : filename;

      const result = await ossClient.put(fullPath, file, {
        meta: {
          ...metadata,
          uploadTime: new Date().toISOString(),
        }
      });

      return {
        url: result.url,
        filename: fullPath
      };
    } catch (error) {
      console.error('OSS upload error:', error);
      throw new Error('文件上传失败');
    }
  }

  // 删除文件
  static async deleteFile(filename: string): Promise<boolean> {
    try {
      await ossClient.delete(filename);
      return true;
    } catch (error) {
      console.error('OSS delete error:', error);
      return false;
    }
  }

  // 批量删除文件
  static async deleteFiles(filenames: string[]): Promise<void> {
    try {
      await ossClient.deleteMulti(filenames);
    } catch (error) {
      console.error('OSS batch delete error:', error);
      throw new Error('批量删除失败');
    }
  }

  // 检查文件是否存在
  static async fileExists(filename: string): Promise<boolean> {
    try {
      await ossClient.head(filename);
      return true;
    } catch (error) {
      return false;
    }
  }

  // 获取文件信息
  static async getFileInfo(filename: string) {
    try {
      const result = await ossClient.head(filename);
      return {
        size: parseInt(result.res.headers['content-length'] || '0'),
        contentType: result.res.headers['content-type'],
        lastModified: result.res.headers['last-modified'],
        etag: result.res.headers.etag,
      };
    } catch (error) {
      throw new Error('获取文件信息失败');
    }
  }
}

环境变量配置

.env.local
# .env.local
OSS_ACCESS_KEY_ID="your_access_key_id_here"
OSS_ACCESS_KEY_SECRET="your_access_key_secret_here"
OSS_REGION="oss-rg-china-mainland"
OSS_BUCKET="your-bucket-name"
BASE_OSS_URL="https://your-bucket-name.oss-rg-china-mainland.aliyuncs.com"

文件上传 API 实现

创建 API 路由来处理文件上传和删除操作,包含文件类型验证、 大小限制和错误处理。

API 路由实现
// app/api/upload/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { OSSManager, generateUniqueFilename } from '@/lib/oss';

export async function POST(request: NextRequest) {
  try {
    const formData = await request.formData();
    const file = formData.get('file') as File;
    const folder = formData.get('folder') as string || 'uploads';

    if (!file) {
      return NextResponse.json(
        { error: '未选择文件' },
        { status: 400 }
      );
    }

    // 检查文件类型
    const allowedTypes = ['image/jpeg', 'image/png', 'image/webp', 'application/pdf'];
    if (!allowedTypes.includes(file.type)) {
      return NextResponse.json(
        { error: '不支持的文件类型' },
        { status: 400 }
      );
    }

    // 检查文件大小 (5MB)
    const maxSize = 5 * 1024 * 1024;
    if (file.size > maxSize) {
      return NextResponse.json(
        { error: '文件大小超过限制' },
        { status: 400 }
      );
    }

    // 生成唯一文件名
    const filename = generateUniqueFilename(file.name);

    // 转换 File 为 Buffer
    const arrayBuffer = await file.arrayBuffer();
    const buffer = Buffer.from(arrayBuffer);

    // 上传到 OSS
    const result = await OSSManager.uploadFile(buffer, filename, {
      folder,
      metadata: {
        originalName: file.name,
        size: file.size.toString(),
        type: file.type,
      }
    });

    return NextResponse.json({
      success: true,
      data: {
        filename: result.filename,
        url: result.url,
        originalName: file.name,
        size: file.size,
        type: file.type,
      }
    });
  } catch (error) {
    console.error('Upload error:', error);
    return NextResponse.json(
      { error: '上传失败' },
      { status: 500 }
    );
  }
}

文件上传演示

体验完整的文件上传流程,包括拖拽上传、进度显示和文件管理

上传文件到 OSS

拖拽文件到此处,或点击选择文件

已上传文件 (3)

profile-photo.jpg

240 KB2024-01-15 10:30:00

document.pdf

1 MB2024-01-15 11:15:00

presentation.pptx

2 MB2024-01-15 14:20:00

图片处理功能

利用 OSS 的图片处理服务实现实时的图片缩放、压缩、格式转换等

图片处理参数

原始图片

原始图片

原始尺寸,未处理

处理后图片

处理后图片

400×30080% • JPG

安全性和最佳实践

安全配置

  • 使用 RAM 用户和最小权限原则
  • 配置 Bucket 访问策略和防盗链
  • 启用服务端加密 (SSE)
  • 使用 HTTPS 传输数据

性能优化

  • 启用 CDN 加速服务
  • 合理规划文件存储结构
  • 使用图片处理服务优化加载
  • 配置生命周期管理规则

OSS 操作练习

尝试编写 OSS 相关代码,掌握文件存储和处理技巧:

OSS 操作练习场

加载编辑器中...

准备好了吗?

现在你已经掌握了阿里云 OSS 的核心功能,让我们继续学习 Zustand 状态管理。

学习 Zustand 状态管理