OSS搭建在线教育视频站:从STS直传到CDN加速的全流程实操
发布时间:2026/9/16 4:14:51 锦皓数字建站

这两年在线教育项目找我咨询的不少五花八门的需求里最核心的就一个视频课程怎么稳定、便宜地存下来还要保证用户观看不卡顿。借着给朋友搭一个视频课程分享站的机会我把阿里云OSS从头到尾过了一遍从Bucket创建、STS直传到视频转码、CDN加速再到权限报错排查踩了一路坑也攒了不少经验。这篇文章就是这次实操的完整记录想用OSS搭在线教育视频站的可以直接照着走。在线教育视频网站最怕两件事视频传不上去、用户打开就卡。OSS解决的就是这两个问题海量存储随便放底层BGP网络全国访问都稳。这篇文章会从架构设计、权限模型、上传链路、视频处理和CDN分发五个方面展开并把我实际遇到的AccessDenied、CORS跨域、图片处理不生效这些常见问题一次性讲清楚。适合正在搭建在线教育网站、想把视频资源放到对象存储上的开发者也适合刚接触OSS不知道从哪下手的初学者。1. 为什么在线教育网站需要OSS1.1 视频课程存储的硬要求在线教育网站的核心资产就是课程视频。视频文件相比普通网页图片、文档有非常明显的特征文件体积大一节45分钟的课压缩后也得300MB到1GB并发访问集中晚上8点上课高峰期用户全挤在一起数据需要长期保留课程版权和持续销售要求文件不能随便清理。这就导致你不能像普通博客一样把文件丢在Web服务器磁盘里。如果自己拿一台云服务器来存视频很快就碰到问题系统盘和数据盘就那么大扩容要停机带宽上不去用户看视频一卡一卡的最麻烦的是防盗链和版权保护要自己从头写。这些其实都能做但投入的精力会远远超出搭一个网站本身的预算。把视频丢进OSS对象存储服务之后架构一下子清爽很多。OSS本身是海量存储单文件最大能到48.8TB存储空间按量扩容根本不用关心磁盘满了会不会挂。视频上传、下载走的是OSS的API同时OSS又支持图片处理、媒体转码、CDN回源、静态网站托管和在线教育的场景匹配度非常高。1.2 为什么不用自建文件服务我见过不少团队选择在自己的云服务器上搭Nginx加磁盘来存课程视频理由是简单、省钱。实际上把账算细一点一台4核8G的服务器数据盘1TB包年大约几百到一千多元看似便宜但要把带宽从5Mbps升到100Mbps费用瞬间翻几倍。更重要的是自建方案每个环节都要自己维护备份策略、磁盘扩容、上传组件、防盗链服务端逻辑全都要写代码。OSS的计费模型完全不一样存储费用加流量费用加请求费用带宽不用你管。OSS的底层是阿里云多线BGP网络全国各地用户访问速度都有保障。上传走内网服务器和OSS同地域时走内网地址完全免费下载走CDN边缘节点就近返回。在在线教育场景下存储量大、下载流量并发高恰恰是OSS最适合的工作负载。1.3 这套方案的适用人群这篇文章适合有几类需求的读者正在搭建在线教育、知识付费网站需要一个稳定、价格可预期的视频存储方案已经有网站想把视频资源从服务器迁移到对象存储上刚接触阿里云OSS想了解Bucket、STS、CDN这些概念怎么在真实项目中落地遇到了AccessDenied、CORS跨域、上传失败这类问题想找排查思路。不管你是用Vue/React的前端还是用SpringBoot/Node写后端下面讲的流程都可以直接用。我这次实操用的是阿里云OSS加CDN配合了一个SpringBoot后端和一个Vue3前端整体流程正好覆盖从账号开通到视频上线的全链路。2. 整体架构设计与权限模型2.1 一个可落地的整体架构先说我这次搭的架构不复杂但每个环节都是必要的前端用Vue3加OSS SDK通过STS临时凭证直传OSS视频播放使用原生H5 Video加CDN加速地址后端用SpringBoot负责用户认证、生成STS临时凭证、管理课程元数据存储方面视频、课程封面图、讲义PDF全部放在OSS分发方面CDN为视频和图片提供加速同时配置HTTPS证书处理方面用OSS的媒体处理功能上传后自动转码、截图封面图自动生成缩略图。这个架构最关键的决策是所有文件流都走OSS后端不经过文件流。上传时浏览器直传OSS播放时浏览器直读OSS或CDN后端只处理签名授权和元数据。这样服务器带宽压力为零前端和后端就算跑在1Mbps带宽的小机器上也没关系。我在实际项目中看到过很多团队走先传后端再传OSS的老路服务器带宽很快被打满视频一多就崩溃其实完全没必要。2.2 Bucket 权限模型公开读还是私有读创建Bucket时有几种权限私有、公共读、公共读写。在线教育视频课程最常见的做法是Bucket设置为私有访问时通过签名URL或STS临时凭证授权如果课程是公开试看可以把对应Object单独设置为公共读或者用CDN做公开分发。我强烈不建议整个Bucket直接设成公共读。一旦设成公共读任何拿到URL的人都可以直接访问搜索引擎也会收录你的课程视频可能被爬走。更细心的做法是媒体文件目录分结构video/free/放试看视频允许公开访问video/pay/放付费课程私有读加CDN鉴权cover/放封面图公共读docs/放讲义私有读。权限控制在OSS里是按先判断后执行的策略Bucket是私有的Object可以单独设公共读Bucket是公共读Object默认也是公共读。所以重点是Bucket别贪图方便设成公共读写平时保持私有精确到Object级别再放开。2.3 AccessKey 与 STS 临时凭证直接在客户端写死AccessKey ID和AccessKey Secret是大忌只要前端被人挖出来整个Bucket就等于裸奔了。正确做法是用RAM子账号加STS临时凭证在阿里云RAM里创建一个子账号只赋予目标Bucket的上传权限后端调用STS的AssumeRole接口传入这个子账号和角色ARN获取临时AccessKey、临时Secret和SecurityToken前端每次上传前先请求后端拿临时凭证然后使用OSS SDK携带临时凭证完成直传。临时凭证默认有效期是3600秒可以根据场景调短或调长。直播课程回看这种批量上传脚本可以设长一点网页上传900秒到1800秒就够避免凭证泄露后长时间有效。这里实际踩过的坑是临时凭证的权限必须用RAM策略精确限制到目录。比如策略里写Resource: acs:oss:*:*:my-bucket/video/pay/*这样即使凭证泄露别人也只能在这个目录下操作不能读全站。后端生成STS的核心代码大概是这样的public OssToken generateStsToken(String objectKey) { DefaultProfile profile DefaultProfile.getProfile( cn-hangzhou, accessKeyId, accessKeySecret); DefaultAcsClient client new DefaultAcsClient(profile); AssumeRoleRequest request new AssumeRoleRequest(); request.setRoleArn(acs:ram::123456789:role/edu-upload-role); request.setRoleSessionName(user-upload-session); request.setDurationSeconds(1800L); // 根据objectKey动态生成最小权限策略 request.setPolicy(generatePolicy(objectKey)); AssumeRoleResponse response client.getAcsResponse(request); return buildToken(response); }注意generatePolicy要把用户上传目录限制死别给全局权限。我在测试时偷懒用过Resource: *一次不小心把AccessKey打到前端控制台结果Bucket里出现了好几GB的垃圾文件清理花了大半天。3. 视频上传链路实操3.1 三步搞定前端直传以网页上传为例整个链路分三步第一步后端返回STS临时凭证。用户上传前前端调用/api/oss/token?objectKeyvideo/pay/what-is-sts.mp4后端校验用户是否有上传权限然后调用STS AssumeRole返回三样东西accessKeyId、accessKeySecret、securityToken同时返回你自己定义的objectKey和上传目录。第二步前端初始化OSS客户端。我用的是阿里云官方ali-ossJavaScript SDK几行代码就能建好客户端import OSS from ali-oss; const client new OSS({ region: oss-cn-hangzhou, bucket: edu-course-video, accessKeyId: resp.accessKeyId, accessKeySecret: resp.accessKeySecret, stsToken: resp.securityToken, secure: true });region是你Bucket所在的地域secure: true表示走HTTPS。如果你开了CDN还可以给endpoint参数传CDN域名让上传全部走CDN回源。第三步调用put上传文件。最简单的用法const result await client.put(objectKey, file, { headers: { Content-Type: file.type } });上传成功后result.url就是Object的访问地址。如果你设置的是私有Bucket这个URL并不能直接播放还需要拼接签名参数或者把这个地址交给后端、让后端生成带签名的URL。3.2 分片上传与断点续传超过100MB的视频强烈建议用分片上传而不是单文件put。分片上传Multipart Upload会把文件切成多个part并发上传单个part推荐1MB到5MB并发数2到4。好处是某个分片失败只需要重试那个分片不用整个文件重传网络断开后还能通过listParts记录断点下次接着传。ali-oss提供了一个更省心的方法multipartUpload可以直接接管分片逻辑const result await client.multipartUpload(objectKey, file, { partSize: 1024 * 1024 * 5, // 5MB per part parallelism: 3, // 并发3个分片 progress(p) { console.log(progress: ${Math.round(p * 100)}%); } });如果你是写Python脚本批量上传历史课程视频oss2也有对应的resumable_upload方法断点续传默认支持。实际项目中上传页面还需要显示进度条。progress回调返回的是0到1的小数可以用它驱动UI进度条。注意分片上传的进度回调在文件较大时可能不是特别均匀UI上可以做平滑处理避免进度条往回跳。3.3 图片自动上传与OSS图片处理很多人问图片自动上传OSS是否可以自动化答案是当然可以。你既可以在代码里调SDK自动上传也可以用命令行工具ossutil写脚本批量上传甚至可以在对象存储控制台手动上传。在在线教育后台课程封面、讲师头像、课件截图的自动上传流程和视频上传代码结构完全一致只需要把objectKey的前缀改成cover/、avatar/就行。上传完成后对课程封面这类图片用OSS的图片处理服务生成不同尺寸的缩略图// 原图访问地址通过图片处理参数生成缩略图 https://cdn.example.com/cover/course-101.jpg?x-oss-processimage/resize,m_fill,w_400,h_225/quality,q_80这一条URL就完成了等比缩放加居中裁剪加压缩质量三个操作不需要你提前准备多张图。关于OSS支持图片模糊处理吗答案是支持。模糊参数长这样?x-oss-processimage/blur,r_10,s_10r是模糊半径s是标准差数值越大越模糊。在线教育里可以用它打码课件里的敏感信息或者做课程试看的模糊预览图。3.4 CORS 跨域配置上传失败的一大来源前端直传OSS时浏览器跨域请求必须有CORS规则否则你会看到类似Access to XMLHttpRequest at ... has been blocked by CORS policy的报错或者put方法直接抛异常。在Bucket的跨域设置里我一般这样配来源写https://www.your-site.com也可以写*但调试期方便线上建议写具体域名允许Methods选GET, POST, PUT, DELETE, HEAD允许Headers写*暴露Headers填ETag, x-oss-request-id缓存时间600秒。这里最容易踩的坑是来源写错。前端页面域名和请求Origin不一致时OSS会拒绝响应。配*虽然快捷但不安全Cookie和带有认证信息的请求会出问题。生产环境务必写精确域名并且把HTTPS和HTTP都考虑进去。4. 视频处理与分发加速4.1 转码、截图、封面生成原始视频格式五花八门不同设备兼容性差异也大直接拿MP4原始文件给播放器要么拖动进度卡顿要么低端手机解码困难。OSS的媒体处理服务可以配合触发器在上传完成后自动转码。我用的方案是给上传管道配置工作流视频上传到video/raw/目录后自动转码成H.264加AAC的MP4分辨率分别输出720p和1080p两个版本并生成一张封面图视频转码通过API或控制台创建转码任务指定宽高和码率视频截图可以指定时间点截取比如第5秒的帧作为课程封面水印给视频打上网站名称或讲师水印防止盗录。转码参数上我一般这样设H.264编码、AAC音频、25fps1080p码率约3500kbps720p码率约2000kbps。码率太低画面糊太高流量费用涨得厉害这两个数值是画质和成本的平衡点。以一节45分钟的课来算1080p版本大约1GB到1.2GB720p版本大约600MB到800MB对大多数课程来说足够清晰了。转码需要消耗转码时长费用但比用户看视频卡顿流失的损失小多了。如果你不想额外用转码服务也可以让用户上传时就转换成统一格式再上传后端校验格式一致性。对大多数中小在线教育团队我建议用OSS媒体处理省心很多。有一点要注意转码后的文件会生成新的Object记得设置不同的目录前缀比如video/transcoded/。否则转码结果容易覆盖原始文件一旦覆盖原文件就找不回来了。4.2 CDN加速与HTTPS证书在线教育视频一定要挂CDN否则OSS原站扛不住大规模并发播放而且OSS的流量单价高于CDN。开通CDN后把域名比如video.your-site.comCNAME到CDN加速域名源站设置为OSS Bucket域名回源HOST填Bucket域名。CDN边缘节点会缓存视频资源用户先从就近节点拉取命中缓存时OSS根本不会被请求到流量成本大幅下降。HTTPS是必须的。浏览器在HTTPS页面里请求HTTP的视频会被视为混合内容直接拦截。CDN控制台可以免费配置证书阿里云也有免费证书服务一年一续流程很简单。注意OSS本身的域名也建议绑定自定义域名并开启HTTPS这样通过OSS直连的图片、文档也不会出现混合内容问题。CDN缓存策略上视频文件我建议缓存时间设置长一点比如30天。课程视频一旦发布内容基本不变长缓存能显著提高命中率。要更新视频时用CDN刷新功能把对应URL刷新掉再重新上传新版本即可。图片文件缓存7天左右比较合适会有换封面的需求文档PDF缓存1天动态接口不要缓存。4.3 防盗链与版权保护纯公开播放的视频任何人都能复制地址转发这基本没法完全杜绝。但我们可以提高扩散成本设置Referer防盗链只允许自己网站域名的请求播放视频防止别人把视频地址嵌入到自己网站私有Bucket加签名URL让后端生成带过期时间的播放地址比如2小时有效视频地址不能长期使用开启CDN的URL鉴权给每个播放地址附加时间戳和签名过期自动失效对高价值课程使用阿里云视频点播的加密转码或接入DRM。我的建议是免费试看视频用Referer防盗链就够了付费课程务必用签名URL加CDN鉴权组合。签名URL的生成原理其实很简单把访问路径、过期时间、AccessKey Secret按规则拼接做HMAC-SHA1签名OSS会校验签名和过期时间。SDK里都封装好了直接调用signatureUrl方法即可。我在后端对付费课程的播放地址统一走了一个接口动态生成5分钟有效的签名URL用户每打开一次课程页面就拿一个新的防止地址被复制散播。5. 常见问题与排查实录5.1 上传失败AccessDenied put public object acl is not allowed这是很多人在网上搜OSS 上传失败:accessdenied: put public object acl is not allowed时会遇到的一个报错。我第一次遇到也很懵后来查了文档才搞清楚这个报错的意思是你在上传时尝试给Object设置公共读ACL但Bucket本身的权限策略不允许这样做。具体触发场景通常是这样的Bucket创建时是私有权限但上传代码或者SDK配置里显式传了headers: {x-oss-object-acl: public-read}或者在控制台上传时勾选了继承Bucket权限之外的选项。OSS的安全机制是Bucket不允许Object越权设置比Bucket更宽松的ACL也就是Bucket私有Object就别想设成公共读。解决方案有两种把Bucket权限调整为公共读但不推荐风险大在RAM授权策略中给子账号加oss:PutObjectAcl权限同时代码里去掉显式ACL头让Object默认继承Bucket的权限需要公开时通过签名URL或CDN鉴权来开放。我的经验是正常在线教育场景代码里永远不要写x-oss-object-acl: public-read这种头让Object继承Bucket权限公开访问全部走CDN或签名URL安全性和灵活性都更好。5.2 上传超时、断点续传失效怎么排查上传大视频时最常见的两个现象一是传了几十MB突然超时二是刷新页面后进度条回到0。先说超时这个通常不是代码问题而是前端请求默认超时时间太短。OSS JS SDK默认超时是60秒对于1GB以上的视频需要调大const client new OSS({ timeout: 600s // 调整为10分钟 });分片上传时单个分片5MB上传遇到弱网也可能超时SDK默认会重试但重试次数有限。可以设置retryMax和retryDelay增加重试策略。再说断点续传。multipartUpload方法本身支持断点续传但只有在同一个uploadId没有过期的情况下才有效。如果你刷新页面后重新走了multipartUploadSDK可能会新建一个uploadId之前的片段就成了孤儿分片。更好的方案是使用服务端记录的uploadId来恢复或者简单一点失败后不要重新初始化客户端保留原来的uploadId继续调用。这里有个实用经验给上传任务增加一个本地记录。每次分片上传成功后把已完成的分片信息存到localStorage或者IndexedDB页面刷新后从断点继续。虽然实现起来多写几十行代码但用户体验提升非常明显。5.3 图片处理参数不生效与访问域名不一致网上很多人搜阿里云OSS支持图片模糊处理吗功能是支持的但不少人在自己域名上调用?x-oss-processimage/blur...发现没效果。原因往往是他们用的是自定义CDN域名而CDN没有开启图片处理功能或者CDN传递查询参数时把x-oss-process过滤掉了。解决办法OSS原生域名访问时确认Bucket开启了图片处理能力控制台有开关使用CDN域名时在CDN回源配置中把x-oss-process参数透传回源某些CDN配置会默认丢弃查询参数需要手动设置自定义域名绑定OSS时别忘了在OSS控制台给该域名授权图片处理权限。基于这个逻辑我建议图片处理统一走OSS原生域名或专门的处理域名和视频播放域名分开。这样哪里出问题排查范围很明确。5.4 常见问题速查表报错信息常见原因解决方案AccessDenied: put public object acl is not allowed上传代码显式设置公共读ACL去掉ACL头改走签名URL或CDNCORS policy blockedBucket CORS规则未配置或来源不匹配配置精确来源域名和Headers403 SignatureDoesNotMatch临时凭证过期或签名参数错误检查STS有效期后端重新签发404 NoSuchKeyobjectKey路径写错或文件未上传核对上传目录和访问路径图片处理不生效CDN丢弃查询参数配置回源参数透传这个表是我在项目上线前自己整理的现在排查问题基本一眼定位。如果你遇到上面没有的情况先把OSS的x-oss-request-id记下来这个是请求唯一的标识提工单时客服第一句话就会问你要这个。5.5 成本控制与生命周期管理OSS虽然便宜但积少成多也容易让月底账单吓一跳。我这次项目里有几个实用的省钱经验存储类型选择频繁访问的课程视频用标准存储很久以前的课程资料、备份归档用低频访问或归档存储。低频访问存储单价只有标准存储的一半左右适合读得少、存得多的场景生命周期规则在Bucket里配置生命周期规则比如视频上传90天后自动转为低频访问存储180天后转为归档存储360天后自动删除临时文件和转码中间产物流量控制开启CDN后OSS的外网流出流量几乎可以忽略。如果仍然有较高的外网流量检查是否有SDK直连OSS下载的请求把它们全部切到CDN域名次数控制OSS的请求费用虽然单次只有几分钱但图片处理、列表请求这类高频操作也会积少成多可以适当加缓存。还有一个小细节阿里云经常给学生、新用户提供免费额度或优惠券如果你是自己学习测试可以先用免费额度把整个链路跑通再正式购买资源我最初就是把免费额度当测试环境整套流程验证完才充值上线的。6. 实操心得与后续扩展这次用OSS搭在线教育视频课程分享网站的实操前前后后折腾了两周最大的感受是对象存储真正解决的不是文件放哪里的问题而是文件怎么安全、高效地流转的问题。权限模型是整条链路的灵魂STS临时凭证加私有Bucket加签名URL这套组合既能保护版权又不牺牲用户体验。CDN是性能的第二保障上了CDN以后晚高峰播放的卡顿率明显下降回源流量也降下来了。如果你正准备做类似的课程分享网站我的建议是从小处着手先开一个Bucket用ossutil命令行工具传两个测试视频把直传、播放、CDN加速这几个环节跑通再慢慢扩展到正式课程。整个过程中把每次遇到的报错截图、把每一次参数调整的原因记下来你会发现自己对OSS的理解会迅速超过绝大多数教程作者的深度。这个项目还有一种扩展方向把视频转码、截图、内容审核全部接入自动化流程后整个课程上架可以做到上传即完成。前端提交视频后后端定时扫描转码状态转码完成后自动通知运营人员审核封面图和预览视频都自动生成。整个链路跑通后在线教育网站最头疼的内容管理环节就真的可以交给云服务了。我这些踩坑记录如果能帮你少走点弯路那就很值了。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。