阿里云 OSS + CDN 加速方案实践

📅 2026-05-28 🏷️ OSS

一、前言

在 Web 应用和 APP 开发中,经常需要存储和分发大量的静态资源,如图片、视频、安装包、文档等。如果这些资源都放在服务器本地,不仅会占用大量服务器存储空间,还会消耗服务器带宽,导致访问速度慢。

阿里云对象存储服务(OSS)是一种海量、安全、低成本、高可靠的云存储服务,配合 CDN 加速使用,可以大幅提升静态资源的访问速度,同时降低服务器成本。

本文将从实际应用角度出发,详细介绍阿里云 OSS + CDN 加速方案的完整实现,包括 OSS 配置、CDN 配置、Java SDK 集成、HTTPS 配置、成本优化等内容。

二、方案概述

2.1 为什么选择 OSS + CDN

  • 存储成本低:OSS 存储成本远低于云服务器的系统盘或数据盘
  • 访问速度快:CDN 全球节点加速,用户从最近的节点获取资源
  • 节省服务器带宽:静态资源走 CDN,不占用服务器带宽
  • 弹性扩展:存储空间和流量按需使用,无需提前规划
  • 高可靠性:OSS 提供 99.9999999999% 的数据可靠性

2.2 整体架构

典型的 OSS + CDN 架构如下:

  1. 用户上传文件 → 应用服务器 → OSS 存储
  2. 用户请求资源 → CDN 节点 → 命中直接返回,未命中回源 OSS
  3. CDN 缓存资源 → 后续请求直接从 CDN 返回

三、OSS 配置

3.1 创建 Bucket

首先需要在阿里云 OSS 控制台创建一个 Bucket(存储空间):

  • Bucket 名称:全局唯一,建议使用业务相关的名称
  • 地域:选择离用户最近的地域
  • 存储类型:标准存储(默认)
  • 读写权限:公共读(用于静态资源分发)
  • 服务端加密:根据需要开启

3.2 获取 AccessKey

为了安全起见,建议创建 RAM 子用户并授权:

  1. 进入 RAM 访问控制控制台
  2. 创建用户,勾选"编程访问"
  3. 记录 AccessKey ID 和 AccessKey Secret
  4. 为用户添加权限:AliyunOSSFullAccess(或更细粒度的权限)

安全提示:AccessKey 是访问 OSS 的密钥,一定要妥善保管,不要泄露到公开场合。建议使用 RAM 子用户,并遵循最小权限原则。

3.3 配置 CORS 跨域

如果前端页面需要直接访问 OSS 资源,需要配置跨域规则:

  • 来源:允许的域名,如 *.example.com
  • 允许 Methods:GET、POST、PUT、DELETE、HEAD
  • 允许 Headers:* 或指定的 header
  • 暴露 Headers:ETag、x-oss-request-id 等
  • 缓存时间:建议 86400 秒(1天)

四、CDN 配置

4.1 添加加速域名

在 CDN 控制台添加加速域名:

  • 加速域名:如 cdn.example.com
  • 业务类型:图片小文件、大文件下载、视音频点播
  • 源站信息:OSS 域名(选择刚才创建的 Bucket)
  • 端口:80 或 443

4.2 配置 CNAME 解析

添加加速域名后,CDN 会分配一个 CNAME 地址。需要在域名 DNS 解析处添加 CNAME 记录:

  • 主机记录:cdn(加速域名的前缀)
  • 记录类型:CNAME
  • 记录值:CDN 分配的 CNAME 地址

4.3 缓存配置

合理配置缓存规则可以提升命中率,降低回源流量:

  • 静态文件(图片、CSS、JS):缓存 30 天
  • 更新不频繁的文件:缓存 7 天
  • 更新频繁的文件:缓存 1 小时或更短
  • 动态内容:不缓存

4.4 HTTPS 配置

CDN 支持免费的 SSL 证书,可以开启 HTTPS 加速:

  1. 在 CDN 控制台的 HTTPS 配置中,选择"免费证书"
  2. 申请 DigiCert 免费证书
  3. 等待证书签发(通常几分钟)
  4. 开启 HTTPS 访问
  5. 建议开启"强制跳转 HTTPS"

4.5 性能优化配置

建议开启以下优化功能:

  • 智能压缩:自动压缩静态文件,减少传输体积
  • 过滤参数:忽略 URL 参数,提高缓存命中率
  • Range 回源:支持断点续传和分片下载
  • 页面优化:自动去除页面空格和注释

五、Java SDK 集成

5.1 添加依赖

在 pom.xml 中添加阿里云 OSS SDK 依赖:

<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.15.1</version>
</dependency>

5.2 配置文件

在 application.properties 中添加配置:

# OSS 配置
oss.endpoint=oss-cn-beijing.aliyuncs.com
oss.accessKeyId=your-access-key-id
oss.accessKeySecret=your-access-key-secret
oss.bucketName=your-bucket-name
oss.cdnDomain=https://cdn.example.com
oss.objectPrefix=images/

5.3 工具类封装

封装一个 OSS 工具类,方便使用:

@Component
public class OssUtil {

    @Value("${oss.endpoint}")
    private String endpoint;

    @Value("${oss.accessKeyId}")
    private String accessKeyId;

    @Value("${oss.accessKeySecret}")
    private String accessKeySecret;

    @Value("${oss.bucketName}")
    private String bucketName;

    @Value("${oss.cdnDomain}")
    private String cdnDomain;

    @Value("${oss.objectPrefix}")
    private String objectPrefix;

    /**
     * 上传文件
     */
    public String uploadFile(MultipartFile file) throws Exception {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            String fileName = file.getOriginalFilename();
            // 生成唯一文件名,避免重名
            String uniqueName = UUID.randomUUID().toString().replace("-", "") 
                + fileName.substring(fileName.lastIndexOf("."));
            String objectKey = objectPrefix + uniqueName;
            
            InputStream inputStream = file.getInputStream();
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(file.getSize());
            metadata.setContentType(file.getContentType());
            
            ossClient.putObject(bucketName, objectKey, inputStream, metadata);
            
            return objectKey;
        } finally {
            ossClient.shutdown();
        }
    }

    /**
     * 删除文件
     */
    public void deleteFile(String objectKey) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            ossClient.deleteObject(bucketName, objectKey);
        } finally {
            ossClient.shutdown();
        }
    }

    /**
     * 获取 CDN 访问 URL
     */
    public String getCdnUrl(String objectKey) {
        if (objectKey == null || objectKey.isEmpty()) {
            return "";
        }
        if (objectKey.startsWith("http://") || objectKey.startsWith("https://")) {
            return objectKey;
        }
        String domain = cdnDomain.endsWith("/") ? cdnDomain : cdnDomain + "/";
        String key = objectKey.startsWith("/") ? objectKey.substring(1) : objectKey;
        return domain + key;
    }
}

5.4 文件上传示例

@RestController
@RequestMapping("/file")
public class FileController {

    @Autowired
    private OssUtil ossUtil;

    @PostMapping("/upload")
    public Result upload(@RequestParam("file") MultipartFile file) {
        try {
            String objectKey = ossUtil.uploadFile(file);
            String cdnUrl = ossUtil.getCdnUrl(objectKey);
            
            Map data = new HashMap<>();
            data.put("objectKey", objectKey);
            data.put("url", cdnUrl);
            
            return Result.success(data);
        } catch (Exception e) {
            return Result.error("上传失败:" + e.getMessage());
        }
    }

    @DeleteMapping("/delete")
    public Result delete(@RequestParam String objectKey) {
        try {
            ossUtil.deleteFile(objectKey);
            return Result.success();
        } catch (Exception e) {
            return Result.error("删除失败:" + e.getMessage());
        }
    }
}

六、高级功能

6.1 图片处理

OSS 提供图片处理功能,可以实时对图片进行缩放、裁剪、水印等操作:

// 图片缩放,宽度 200px
String url = ossUtil.getCdnUrl(objectKey) + "?x-oss-process=image/resize,w_200";

// 图片裁剪,宽高 100x100
String url = ossUtil.getCdnUrl(objectKey) + "?x-oss-process=image/crop,w_100,h_100";

// 添加文字水印
String url = ossUtil.getCdnUrl(objectKey) + "?x-oss-process=image/watermark,text_SGVsbG8=";

6.2 签名 URL

对于私有 Bucket,可以生成签名 URL 进行临时访问:

/**
 * 生成签名URL(私有Bucket使用)
 */
public String generatePresignedUrl(String objectKey, long expirationMinutes) {
    OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    try {
        Date expiration = new Date(System.currentTimeMillis() + expirationMinutes * 60 * 1000);
        URL url = ossClient.generatePresignedUrl(bucketName, objectKey, expiration);
        return url.toString();
    } finally {
        ossClient.shutdown();
    }
}

6.3 分片上传

对于大文件,建议使用分片上传,支持断点续传:

// 初始化分片上传
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectKey);
InitiateMultipartUploadResult result = ossClient.initiateMultipartUpload(request);
String uploadId = result.getUploadId();

// 上传分片
List partETags = new ArrayList<>();
for (int i = 0; i < partCount; i++) {
    UploadPartRequest uploadPartRequest = new UploadPartRequest();
    uploadPartRequest.setBucketName(bucketName);
    uploadPartRequest.setKey(objectKey);
    uploadPartRequest.setUploadId(uploadId);
    uploadPartRequest.setInputStream(inputStream);
    uploadPartRequest.setPartSize(partSize);
    uploadPartRequest.setPartNumber(i + 1);
    
    UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
    partETags.add(uploadPartResult.getPartETag());
}

// 完成分片上传
CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest(
    bucketName, objectKey, uploadId, partETags);
ossClient.completeMultipartUpload(completeRequest);

七、成本优化

7.1 存储成本优化

  • 生命周期管理:将不常访问的文件转为低频访问或归档存储
  • 定期清理:定期删除无用的临时文件和过期文件
  • 图片压缩:上传前压缩图片,减少存储空间

7.2 流量成本优化

  • 开启 CDN:CDN 流量比 OSS 外网流量便宜
  • 提高缓存命中率:合理设置缓存时间,减少回源
  • 开启智能压缩:减少传输体积
  • 购买流量包:流量包比按量付费更划算

7.3 成本估算示例

以一个中等规模的 APP 为例,每月成本估算:

  • 存储:100GB × 0.12元/GB = 12元/月
  • CDN 流量:500GB × 0.2元/GB = 100元/月(流量包更便宜)
  • 请求费用:约 5元/月
  • 合计:约 117元/月

相比服务器带宽,成本降低很多,而且访问速度更快。

八、常见问题

8.1 CDN 缓存更新

文件更新后,CDN 节点的缓存不会立即更新。可以通过以下方式刷新:

  • URL 刷新:强制刷新指定 URL
  • 目录刷新:刷新整个目录
  • 版本号方案:文件名加版本号,如 image-v2.jpg

8.2 防盗链配置

为了防止资源被其他网站盗用,可以配置防盗链:

  • Referer 白名单:只允许指定域名访问
  • 空 Referer 允许:允许浏览器直接访问
  • CDN 也可以配置防盗链

8.3 跨域问题

前端访问 OSS 或 CDN 出现跨域错误时,检查:

  • OSS 是否配置了 CORS 规则
  • CDN 是否配置了跨域头
  • 域名是否在允许列表中

九、安全建议

  • 使用 RAM 子用户,遵循最小权限原则
  • 定期轮换 AccessKey
  • 开启服务端加密,保护数据安全
  • 配置防盗链,防止资源被盗用
  • 私有 Bucket 使用签名 URL 访问
  • 开启日志记录,便于审计和问题排查

十、总结

阿里云 OSS + CDN 是一套成熟的静态资源存储和分发方案,具有成本低、速度快、可靠性高等优点,非常适合用于图片、视频、安装包等静态资源的托管。

本文介绍了 OSS 和 CDN 的配置方法、Java SDK 集成、高级功能、成本优化等内容。在实际使用中,建议根据业务需求选择合适的配置,并定期监控使用量和成本。

希望本文能帮助大家快速上手 OSS + CDN 方案。如有问题,欢迎在评论区交流讨论。