如何使用AccessKeyId和SecretAccessKey在浏览器中访问AWS S3存储桶文件?
实现S3视频在React前端播放的完整步骤
1. 前置S3存储桶配置
绝对不要将AccessKeyId、SecretAccessKey硬编码到前端代码中,会直接导致密钥泄露、资产被盗刷
- 配置S3桶CORS规则,允许前端域名跨域访问,示例配置如下:
[ { "AllowedHeaders": ["*"], "AllowedMethods": ["GET"], "AllowedOrigins": ["https://你的前端域名.com", "http://localhost:3000"], // 开发环境可加localhost "ExposeHeaders": ["ETag", "Content-Length", "Content-Range"], "MaxAgeSeconds": 3600 } ]
- 给AccessKeyId绑定的IAM用户配置最小权限,仅开放
s3:GetObject权限即可,无需额外权限。 - 不要开启存储桶公共访问权限,所有视频访问通过后端生成的预签名URL实现。
2. NestJS后端实现(生成预签名播放URL)
2.1 安装依赖
npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
2.2 编写S3服务
在Nest项目中新增S3服务,通过环境变量读取AWS配置(不要硬编码密钥):
import { Injectable } from '@nestjs/common'; import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; @Injectable() export class S3Service { private s3Client: S3Client; constructor() { this.s3Client = new S3Client({ region: process.env.AWS_REGION, credentials: { accessKeyId: process.env.AWS_ACCESS_KEY_ID, secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, }, }); } async getVideoPlayUrl(fileName: string, expiresIn = 3600) { const command = new GetObjectCommand({ Bucket: process.env.AWS_S3_BUCKET_NAME, Key: fileName, }); // 生成有效期默认为1小时的预签名URL return getSignedUrl(this.s3Client, command, { expiresIn }); } }
2.3 提供对外接口
编写Controller对外暴露获取播放地址的接口,可自行添加权限校验逻辑:
import { Controller, Get, Query } from '@nestjs/common'; import { S3Service } from './s3.service'; @Controller('video') export class VideoController { constructor(private readonly s3Service: S3Service) {} @Get('play-url') async getPlayUrl(@Query('fileName') fileName: string) { // 此处可添加权限校验,比如判断当前登录用户是否有权限访问该视频 const url = await this.s3Service.getVideoPlayUrl(fileName); return { playUrl: url }; } }
3. React前端实现视频播放
你可以直接用原生HTML5 video标签,也可以用第三方播放器如react-player适配更多场景:
3.1 原生video标签实现示例
import { useEffect, useState } from 'react'; const VideoPlayer = ({ fileName }: { fileName: string }) => { const [playUrl, setPlayUrl] = useState(''); useEffect(() => { // 调用后端接口获取预签名URL fetch(`/api/video/play-url?fileName=${encodeURIComponent(fileName)}`) .then(res => res.json()) .then(data => setPlayUrl(data.playUrl)); }, [fileName]); if (!playUrl) return <div>加载中...</div>; return ( <video src={playUrl} controls width="100%" preload="metadata" /> ); }; export default VideoPlayer;
3.2 react-player实现示例
如果需要支持更多格式、自定义播放控件,可以安装react-player:
npm install react-player
对应组件代码:
import ReactPlayer from 'react-player'; // 其他逻辑和原生实现一致,替换渲染部分即可 return <ReactPlayer url={playUrl} controls width="100%" />;
常见问题排查
- 跨域报错:检查S3 CORS规则中的AllowedOrigins是否包含当前前端域名,是否允许GET请求
- 视频无法加载:检查预签名URL是否过期,IAM用户是否有对应文件的GetObject权限,文件名是否正确
- 进度条拖动失效:检查CORS规则是否暴露了Content-Range响应头,S3是否正常响应range请求
内容的提问来源于stack exchange,提问作者Gerald
相关产品推荐
相关产品推荐

