ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Spring Boot + Vue 实现个人视频管理:从上传到播放的完整链路

Spring Boot + Vue 实现个人视频管理:从上传到播放的完整链路 在实际开发里“我的视频”这类个人视频管理项目经常被低估。很多开发者以为只要有一个 HTML5video标签把视频地址填进去就能播放真正动手做时才发现视频文件存在哪里、接口怎么返回、浏览器用什么编码格式播放、上传大文件会不会超时、前端页面怎么刷新列表每一条链路都会影响最终效果。这篇文章就以“我的视频”为一个最小可运行的个人视频管理项目拆开完整的实现过程后端负责上传和文件存储前端负责列表展示和播放器集成。读者跟着做完后能掌握一个可复用的 Spring Boot Vue 视频管理雏形并能在本地环境完成上传、列表、播放验证。项目不依赖付费服务也不接入第三方存储重点是把“本地视频文件 - HTTP 接口 - 浏览器播放器”这条链路跑通。生产化需要考虑的转码、对象存储、CDN 和权限问题会放在最后单独说明。这样处理既适合刚开始接触前后端联调的学习者也适合想快速搭建内部视频管理工具的后端工程师。1. 先理清“我的视频”项目的需求与技术链路1.1 需求拆解本地视频怎么变成在线可播放一个个人视频管理页面的核心需求可以拆成四部分上传视频、保存视频信息、展示视频列表、点击视频后能在线播放。看似简单但每一部分背后都有细节。上传视频时前端表单需要把文件通过 HTTP 发送给后端。后端不能只把文件写到磁盘就结束还要保存视频的元数据比如标题、文件大小、上传时间、存储路径。这样列表页才有内容可展示。展示列表时前端从后端拉取结构化数据渲染成卡片或表格。为了能播放后端必须把视频文件通过可访问的 URL 暴露给前端比如/upload/2024/05/xxx.mp4。前端拿到这个 URL 后交给video标签播放。这里最关键的问题是“浏览器能不能播放”。浏览器对视频格式有严格要求不是所有.mp4都能播放。最常见的原因是视频编码不是 H.264或者音频编码不是 AAC。缺少转码模块时项目中要在上传环节做提示或在文档中明确推荐使用 H.264 视频编码。1.2 技术选型为什么用 Spring Boot Vue HTML5 video这个项目选择 Spring Boot 作为后端Vue 3 作为前端播放器使用浏览器原生video原因主要有三点。第一Spring Boot 能快速提供文件上传、静态资源映射和 JSON 接口。文件上传只需要处理MultipartFile不需要额外引入重型框架。静态资源映射可以配置本地目录让视频文件直接通过 URL 访问。第二Vue 3 的响应式列表渲染非常适合这个场景。上传后返回新的视频记录列表会自动更新切换播放器地址时不需要刷新页面。第三原生video已经覆盖个人项目的播放需求。相比接入第三方播放器原生标签的兼容性更可控代码量也更少。这个组合不是唯一选择Python 的 FastAPI 配 React 同样可行。这里的重点是讲解通用链路技术栈只作为示例。1.3 目录结构和数据模型要提前设计项目建议采用前后端分离目录但本地开发时可以放在同一个父目录下方便统一管理my-video/ ├── backend/ # Spring Boot 工程 │ ├── src/main/java/... │ └── src/main/resources/application.yml ├── frontend/ # Vue 3 工程 │ ├── src/ │ │ ├── api/video.js │ │ ├── App.vue │ │ └── main.js │ ├── index.html │ └── package.json └── upload/ # 视频文件实际存储目录数据模型方面数据库只需要一张video_info表。字段设计不追求多但要把播放必需的信息都包含进来字段类型说明idBIGINT主键自增titleVARCHAR视频标题展示用descriptionVARCHAR视频描述可选file_nameVARCHAR上传时的原始文件名stored_nameVARCHAR后端重命名后的存储文件名file_pathVARCHAR相对于上传根目录的路径file_sizeBIGINT文件大小单位字节content_typeVARCHARMIME 类型created_atDATETIME创建时间updated_atDATETIME更新时间这里的stored_name和file_name分开存储是为了避免直接使用用户上传的文件名写入磁盘。原始文件名只用于展示存储文件名由后端生成 UUID避免重名和路径注入风险。2. 环境准备与项目初始化2.1 后端环境版本说明示例工程以 Spring Boot 3.2 和 JDK 17 为基础。如果本地是 Spring Boot 2.x需要注意两点第一包名是javax.*而不是jakarta.*第二跨域配置和文件上传配置的写法基本相同。推荐环境如下软件版本/用途JDK17 或以上Maven3.8 或以上Spring Boot3.2.xNode.js18 或以上npm9 或以上Vue3.xVite4.x 或 5.x不强制所有读者都用相同版本。只要理解代码中的jakarta.servlet.http.HttpServletResponse、org.springframework.web.multipart.MultipartFile等关键类换版本时也能快速调整。2.2 初始化 Spring Boot 后端工程在 start.spring.io 或 IDE 中创建项目时只需要添加一个依赖Spring Web。其他依赖如 MySQL 驱动、MyBatis 或 JPA可以按自己的持久化方案添加。为了让示例足够简洁这里先使用 Spring Data JPA 和 H2 内存数据库。这样不需要安装 MySQL 就能跑通流程。若要在生产环境切换 MySQL只需要修改数据源配置。pom.xml的核心依赖如下dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency dependency groupIdcom.h2database/groupId artifactIdh2/artifactId scoperuntime/scope /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId optionaltrue/optional /dependency /dependencies如果不想使用 JPA也可以直接使用 Spring JDBC 或 MyBatis。这里选 JPA 是因为实体类代码最少更适合快速演示。2.3 配置文件上传目录、文件大小和静态资源映射src/main/resources/application.yml是后端的核心配置。文件上传目录建议放在项目根目录之外便于备份也避免打包进 JAR。server: port: 8080 spring: application: name: my-video servlet: multipart: max-file-size: 500MB max-request-size: 500MB h2: console: enabled: true path: /h2-console datasource: url: jdbc:h2:file:./data/myvideo driver-class-name: org.h2.Driver username: sa password: jpa: hibernate: ddl-auto: update show-sql: true my-video: upload-dir: ./uploadmax-file-size和max-request-size直接影响大文件上传。Spring Boot 默认的 1MB 限制对于视频文件远远不够。这里设置到 500MB只适合本地演示。生产环境一般不会用同步上传接 500MB 文件而是走分片上传或对象存储直传。my-video.upload-dir是自定义配置项用于读取上传存储目录。这样配置和代码可以分离部署时通过环境变量覆盖。2.4 创建数据库表结构使用 JPA 后可以直接用实体类自动建表。也可以准备一份 DDL方便切换到 MySQLCREATE TABLE video_info ( id BIGINT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255) NOT NULL, description VARCHAR(1000), file_name VARCHAR(255) NOT NULL, stored_name VARCHAR(255) NOT NULL, file_path VARCHAR(500) NOT NULL, file_size BIGINT NOT NULL, content_type VARCHAR(255), created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL );这张表不存视频二进制内容只存文件路径。视频文件本身在upload目录数据库里的file_path用于拼接访问 URL。这样数据库不会迅速膨胀备份时可以只备份数据库视频文件通过文件系统备份。3. 后端实现视频元数据接口和静态资源服务3.1 实体类与 Repository先创建视频信息实体类。字段与前面 DDL 对齐。package com.example.myvideo.entity; import jakarta.persistence.*; import lombok.Data; import java.time.LocalDateTime; Data Entity Table(name video_info) public class VideoInfo { Id GeneratedValue(strategy GenerationType.IDENTITY) private Long id; private String title; private String description; Column(name file_name) private String fileName; Column(name stored_name) private String storedName; Column(name file_path) private String filePath; Column(name file_size) private Long fileSize; Column(name content_type) private String contentType; Column(name created_at) private LocalDateTime createdAt; Column(name updated_at) private LocalDateTime updatedAt; PrePersist public void prePersist() { LocalDateTime now LocalDateTime.now(); this.createdAt now; this.updatedAt now; } PreUpdate public void preUpdate() { this.updatedAt LocalDateTime.now(); } }Repository 接口只使用内置方法即可。package com.example.myvideo.repository; import com.example.myvideo.entity.VideoInfo; import org.springframework.data.jpa.repository.JpaRepository; public interface VideoInfoRepository extends JpaRepositoryVideoInfo, Long { }这个接口提供findAll()和save()方法已经足够覆盖列表和上传场景。3.2 业务服务保存文件并写入元数据VideoService负责文件存储和数据库写入。核心方法有三步生成存储名、保存文件、写入数据库。package com.example.myvideo.service; import com.example.myvideo.entity.VideoInfo; import com.example.myvideo.repository.VideoInfoRepository; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.core.io.UrlResource; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.Objects; import java.util.UUID; Service public class VideoService { private final VideoInfoRepository repository; Value(${my-video.upload-dir}) private String uploadDir; public VideoService(VideoInfoRepository repository) { this.repository repository; } public VideoInfo uploadVideo(String title, String description, MultipartFile file) { try { Path uploadPath Paths.get(uploadDir).toAbsolutePath().normalize(); Files.createDirectories(uploadPath); String originalFilename Objects.requireNonNull(file.getOriginalFilename(), 文件名不能为空); String extension getExtension(originalFilename); String storedName UUID.randomUUID() extension; Path targetPath uploadPath.resolve(storedName); file.transferTo(targetPath); VideoInfo info new VideoInfo(); info.setTitle(title); info.setDescription(description); info.setFileName(originalFilename); info.setStoredName(storedName); info.setFilePath(storedName); info.setFileSize(file.getSize()); info.setContentType(file.getContentType()); return repository.save(info); } catch (Exception e) { throw new RuntimeException(视频保存失败, e); } } public ListVideoInfo listVideos() { return repository.findAll(); } private String getExtension(String filename) { int dotIndex filename.lastIndexOf(.); return dotIndex 0 ? filename.substring(dotIndex).toLowerCase() : ; } }这里有几个关键点。storedName使用 UUID避免两个文件重名。Files.createDirectories保证目录存在。file.transferTo是 Spring 推荐的文件保存方式能自动处理临时文件和资源释放。getExtension只提取后缀不信任原始文件名本身。3.3 控制器上传接口和列表接口控制器对外暴露两个接口POST /api/videos用于上传GET /api/videos用于列表。视频文件访问不放在控制器里而是交给静态资源映射处理。package com.example.myvideo.controller; import com.example.myvideo.entity.VideoInfo; import com.example.myvideo.service.VideoService; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.util.List; RestController RequestMapping(/api/videos) public class VideoController { private final VideoService videoService; public VideoController(VideoService videoService) { this.videoService videoService; } PostMapping(consumes MediaType.MULTIPART_FORM_DATA_VALUE) public VideoInfo upload(RequestParam(title) String title, RequestParam(value description, required false) String description, RequestParam(file) MultipartFile file) { return videoService.uploadVideo(title, description, file); } GetMapping public ListVideoInfo list() { return videoService.listVideos(); } }使用RequestParam接收上传表单时前端必须按下划线方式传参。后面 Vue 代码会用到FormData字段名要与这里保持一致。3.4 静态资源映射让视频文件能通过 URL 播放视频不能只保存在本地前端必须能请求到文件。Spring Boot 可以通过WebMvcConfigurer配置将本地目录映射到/upload/**。package com.example.myvideo.config; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.nio.file.Paths; Configuration public class WebConfig implements WebMvcConfigurer { Value(${my-video.upload-dir}) private String uploadDir; Override public void addResourceHandlers(ResourceHandlerRegistry registry) { String location Paths.get(uploadDir).toAbsolutePath().normalize().toUri().toString(); registry.addResourceHandler(/upload/**) .addResourceLocations(location); } }配置完成后假设上传目录是./upload存储文件是abc.mp4那么访问地址为http://localhost:8080/upload/abc.mp4。注意addResourceLocations必须以/结尾。toUri().toString()会返回类似file:///User/xxx/upload/的路径符合要求。很多视频无法播放的问题都是因为这个配置漏了结尾斜杠或路径拼接错误。3.5 跨域配置前端开发服务器运行在5173端口后端运行在8080端口浏览器会拦截跨域请求。这里需要配置后端允许跨域或者在前端使用代理。简单演示时可以在后端加一个全局 CORS 配置。package com.example.myvideo.config; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/api/**) .allowedOrigins(http://localhost:5173) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*); } }allowedOrigins在开发环境可以直接写前端地址。生产环境上线后建议改成具体域名或直接通过 Nginx 反向代理避免跨域问题从源头出现。4. 前端实现视频列表与播放器页面4.1 初始化 Vue 3 项目使用 Vite 创建前端工程npm create vitelatest frontend -- --template vue cd frontend npm install安装请求库 axiosnpm install axios开发环境下为了避免跨域可以在vite.config.js中配置代理。这样前端请求/api时Vite 会转发到后端8080。import { defineConfig } from vite import vue from vitejs/plugin-vue export default defineConfig({ plugins: [vue()], server: { port: 5173, proxy: { /api: { target: http://localhost:8080, changeOrigin: true }, /upload: { target: http://localhost:8080, changeOrigin: true } } } })代理的好处是前端代码里不需要写后端完整地址统一使用相对路径。发布时再把静态文件交给 Nginx同样代理/api和/upload到后端服务即可。4.2 封装请求模块src/api/video.js把后端接口封装成两个函数。import axios from axios const http axios.create({ baseURL: /api, timeout: 60000 }) export function listVideos() { return http.get(/videos) } export function uploadVideo(formData) { return http.post(/videos, formData, { headers: { Content-Type: multipart/form-data } }) }上传时间太长时60 秒可能不够。如果文件较大建议把请求timeout设置更长或者采用分片上传。这个示例为了简单只调整了超时时间。4.3 视频播放器组件播放器组件接收一个url属性根据地址变化切换播放内容。使用video controls是原生播放器不需要额外引入库。template div classplayer video v-ifurl :srcurl controls preloadmetadata stylewidth: 100%; max-height: 480px; background: #000 /video div v-else classempty 请选择视频 /div /div /template script setup defineProps({ url: { type: String, default: } }) /scriptpreloadmetadata表示只预加载视频元数据避免一打开页面就下载整个视频文件。controls属性提供浏览器自带的播放控制条包含播放、音量、全屏等功能。4.4 主页面上传表单和视频列表App.vue负责页面整体布局。页面分成两部分左侧是上传区右侧是列表和播放器。为了演示完整流程不引入 UI 组件库直接用原生表单。template main classpage h1我的视频/h1 section classupload-box h2上传视频/h2 form submit.preventhandleUpload input v-modeltitle placeholder视频标题 required / input v-modeldescription placeholder视频描述 / input typefile acceptvideo/* changehandleFileChange required / button typesubmit :disableduploading {{ uploading ? 上传中... : 开始上传 }} /button /form /section section classvideo-panel aside classvideo-list h2全部视频/h2 ul li v-forvideo in videos :keyvideo.id :class{ active: currentUrl buildPlayUrl(video) } clickplayVideo(video) span classtitle{{ video.title }}/span span classsize{{ formatSize(video.fileSize) }}/span /li /ul /aside section classvideo-stage VideoPlayer :urlcurrentUrl / /section /section /main /template script setup import { onMounted, ref } from vue import { listVideos, uploadVideo } from ./api/video import VideoPlayer from ./components/VideoPlayer.vue const videos ref([]) const title ref() const description ref() const selectedFile ref(null) const uploading ref(false) const currentUrl ref() async function loadVideos() { const { data } await listVideos() videos.value data } function handleFileChange(event) { selectedFile.value event.target.files[0] } async function handleUpload() { if (!selectedFile.value) return uploading.value true try { const formData new FormData() formData.append(title, title.value) formData.append(description, description.value) formData.append(file, selectedFile.value) await uploadVideo(formData) title.value description.value selectedFile.value null await loadVideos() } finally { uploading.value false } } function buildPlayUrl(video) { return /upload/${video.filePath} } function playVideo(video) { currentUrl.value buildPlayUrl(video) } function formatSize(size) { const mb size / 1024 / 1024 if (mb 1024) { return (mb / 1024).toFixed(2) GB } return mb.toFixed(2) MB } onMounted(loadVideos) /script style scoped .page { max-width: 1200px; margin: 0 auto; padding: 20px; } .upload-box { margin-bottom: 20px; padding: 16px; border: 1px solid #ddd; border-radius: 8px; } form { display: flex; gap: 12px; flex-wrap: wrap; } input[typetext], input[typefile] { padding: 8px; border: 1px solid #ccc; border-radius: 4px; } .video-panel { display: flex; gap: 20px; } .video-list { width: 300px; } .video-list ul { list-style: none; padding: 0; } .video-list li { padding: 10px; border: 1px solid #eee; border-radius: 6px; cursor: pointer; margin-bottom: 8px; } .video-list li.active { border-color: #1890ff; background: #e6f7ff; } .video-stage { flex: 1; } /style注意buildPlayUrl使用相对路径/upload/...开发时 Vite 代理会转发到后端。这一步是很多初学容易忽略的地方前端拿到的视频地址必须是浏览器可直接访问的 URL而不是数据库里的物理路径。5. 运行验证与请求链路分析5.1 启动后端和前端在backend目录启动 Spring Bootmvn spring-boot:run在frontend目录启动前端npm run dev浏览器访问http://localhost:5173页面应该显示“我的视频”此时视频列表为空。5.2 上传视频验证准备一个 MP4 文件建议使用 H.264 编码、编码格式为 AAC 的普通视频。填写标题选择文件点击上传。预期结果页面提示“上传中...”后自动刷新列表。后端日志出现INSERTSQL 语句。upload目录出现新的视频文件文件名是一串 UUID。可以通过接口验证curl -X GET http://localhost:5173/api/videos返回结果类似[ { id: 1, title: 我的旅行记录, description: 假期视频, fileName: travel.mp4, storedName: 9f8c2f4e-1a2b-4c3d-8e9f-abcdef123456.mp4, filePath: 9f8c2f4e-1a2b-4c3d-8e9f-abcdef123456.mp4, fileSize: 12582912, contentType: video/mp4, createdAt: 2025-05-01T12:00:00, updatedAt: 2025-05-01T12:00:00 } ]5.3 播放视频验证点击列表中的视频条目播放器区域应该出现可播放的视频画面。可以直接访问视频地址验证curl -I http://localhost:5173/upload/xxx.mp4如果返回200 OK并且响应头包含Content-Type: video/mp4说明静态资源映射生效。如果返回404需要检查后端WebConfig中的路径配置。播放时打开浏览器开发者工具重点观察 Network 请求状态。视频首次播放时浏览器会发起Range请求响应状态通常是206 Partial Content这是正常的表示浏览器支持分段加载视频内容。6. 常见问题与排查链路6.1 视频文件能上传但播放器一直转圈或报错现象上传成功后列表有数据点击播放视频没有画面控制台显示请求失败或video format not supported。排查顺序直接用浏览器访问视频 URL检查是否能下载文件。检查响应头的Content-Type是否是video/mp4。检查视频编码。打开视频文件的编码信息确认视频轨是 H.264音频轨是 AAC。如果是 H.265、VP9 或其他编码浏览器可能无法播放。检查是否存在大小超过 2GB 的情况。本地文件系统对FileOutputStream不敏感但播放器对文件范围请求有要求遇到异常需要看响应头。解决建议问题现象常见原因处理方式播放器转圈URL 返回 404 或后端未启动检查静态资源映射和代理配置格式不支持视频编码非 H.264使用 FFmpeg 转码为 H.264 AAC卡顿严重本地网络或文件过大压缩码率或使用 CDN 分发6.2 上传或请求接口出现跨域问题现象浏览器控制台出现No Access-Control-Allow-Origin header接口请求失败。可能原因前端5173直接请求了后端8080而代理没有生效或者代理配置了但请求路径不匹配。检查方式确认访问的是http://localhost:5173/api/videos不是http://localhost:8080/api/videos。确认vite.config.js中的代理配置已经重启 Vite。确认后端 CORS 配置允许的源包含http://localhost:5173。推荐做法是使用代理而不是把baseURL写成http://localhost:8080。代理能减少大量跨域问题。6.3 上传大文件时提示文件大小超过限制现象上传小于 1MB 的视频没有问题超过一定大小后报错FileSizeLimitExceededException。原因Spring Boot 默认限制单次上传文件大小为 1MB。示例中已经在application.yml配置了 500MB但如果读者复制时遗漏或使用 Spring Boot 2.x 的默认配置就会命中限制。解决方式spring: servlet: multipart: max-file-size: 500MB max-request-size: 500MB同时要注意 Nginx 层也有client_max_body_size限制。如果经过 Nginx需要在 Nginx 配置中增加client_max_body_size 500m;6.4 重新部署后上传文件丢失或目录不存在现象重启后端后列表里有记录但打开视频 404或者上传报系统找不到指定的路径。可能原因上传目录使用了相对路径而启动目录变化导致路径不一致。解决方式不要使用相对路径作为生产存储目录。最稳妥的方式是用 Spring Boot 配置项指定绝对路径例如my-video: upload-dir: /data/my-video/upload部署前要确认该目录存在并且运行后端的用户有读写权限。强烈建议在配置中增加目录检查启动时找不到目录就创建并记录日志。7. 生产化扩展与最佳实践7.1 本地项目可以先跑通但生产环境要补安全底线示例中的接口没有鉴权任何人只要能访问后端就能上传和删除视频。如果项目要对外提供访问至少需要增加一层登录认证。推荐做法使用 Spring Security 登录认证上传和删除接口需要管理员权限。视频访问地址不要直接暴露完整存储路径可以增加签名 URL 或鉴权拦截器。只允许特定扩展名比如.mp4、.webm并在上传时校验 MIME 类型和文件头。限制单文件大小避免磁盘被恶意文件塞满。7.2 视频转码是必不可少的扩展个人项目可以手动准备 H.264 视频但真实用户上传的视频编码五花八门。为了兼容浏览器建议引入 FFmpeg 转码流程。最简单的转码命令ffmpeg -i input.mp4 -c:v libx264 -c:a aac -preset fast -movflags faststart output.mp4-movflags faststart会把 MP4 的元数据移动到文件开头让浏览器无需下载完整文件就可以开始播放。这个参数对 Web 播放非常关键。如果不想自己维护转码集群可以接入云厂商的媒体处理服务。但即便使用云服务也要理解“浏览器要求 H.264 编码”这个前提否则排错时无从下手。7.3 存储与分发从本地磁盘走向对象存储和 CDN本地磁盘在文件量少时够用但它有两个明显瓶颈容量有限、单点故障。生产环境建议分两步演进。第一步把视频文件迁移到对象存储数据库只保存对象存储的 Key。上传接口不再直接保存到本地而是流式写入对象存储。播放地址直接使用对象存储提供的 URL。第二步给播放地址接入 CDN。视频文件流量大通过 CDN 可以降低源站压力同时提升不同地区用户的播放体验。需要注意的是私有视频不能直接在 CDN 上公开需要配置 URL 鉴权或者临时签名。7.4 上线前可复用的检查清单下面的清单可以直接作为项目上线前的手工检查表检查项检查内容数据库表结构是否创建索引是否合理备份策略是否生效存储目录是否使用绝对路径目录权限是否正确磁盘空间是否充足文件上传单文件大小限制是否符合业务是否校验扩展名和 MIME视频格式是否包含转码流程是否输出 H.264 AAC访问地址视频 URL 是否为可公开访问地址是否包含鉴权代理层Nginx 是否配置client_max_body_size代理路径是否正确日志监控上传失败日志是否完整磁盘和带宽是否纳入监控回滚方案后端版本回滚是否能保证数据库和文件目录兼容这个项目最大的价值不是“做一个视频网站”而是把上传、存储、接口、播放、排错这一整条链路完整走通。掌握这条链路之后无论是改成图片管理、音频管理还是接入云存储思路都是一样的。下一步最值得做的扩展是给项目加入 FFmpeg 转码队列把“能存文件”升级成“能处理用户的真实视频文件”。对新手来说先把本节的最小闭环跑通再逐步补上安全、转码和存储优化学习曲线会平滑很多。
返回列表