如何为Vue的videojs-player中原生<video>元素注入认证请求头?
解决Vue中videojs-player请求DRF视频接口401的问题
下面给你几个实用的解决思路,按需选择:
方案一:通过axios请求视频Blob再生成URL(适合小体积视频)
利用axios自动携带认证头的特性,先请求视频数据转为Blob,再生成临时URL给videojs使用,避免原生video直接请求不带头的问题。
示例代码:
<template> <video-player ref="videoPlayer" :options="playerOptions"></video-player> </template> <script> import axios from 'axios' import VideoPlayer from '@videojs-player/vue' export default { components: { VideoPlayer }, data() { return { playerOptions: { sources: [] }, videoUrl: '/api/videos/1/' // 你的DRF视频接口地址 } }, async mounted() { try { // 用axios请求视频,responseType设为blob const response = await axios.get(this.videoUrl, { responseType: 'blob' }) // 生成Blob URL const blobUrl = URL.createObjectURL(response.data) // 更新videojs的源 this.playerOptions.sources = [{ src: blobUrl, type: 'video/mp4' // 根据你的视频格式调整 }] // 手动触发组件更新 this.$nextTick(() => { this.$refs.videoPlayer.player.load() }) } catch (err) { console.error('加载视频失败:', err) } }, beforeUnmount() { // 记得清理Blob URL,避免内存泄漏 if (this.playerOptions.sources[0]?.src) { URL.revokeObjectURL(this.playerOptions.sources[0].src) } } } </script>
方案二:用Service Worker拦截视频请求添加认证头(适合大体积视频)
通过Service Worker拦截所有视频资源请求,手动在请求头里加上Authorization字段,这样原生video的请求就会自动带认证头了。
- 注册Service Worker(在Vue项目的main.js里):
if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js') .then(registration => { console.log('SW registered: ', registration) }) .catch(registrationError => { console.log('SW registration failed: ', registrationError) }) }) }
- 编写sw.js文件(放在项目public目录下):
self.addEventListener('fetch', (event) => { const request = event.request // 判断是否是视频请求,根据你的接口路径调整规则 if (request.url.includes('/api/videos/') && request.method === 'GET') { // 克隆请求,避免原请求被修改 const modifiedRequest = new Request(request, { headers: new Headers(request.headers) }) // 添加Bearer Token,这里从localStorage取你存的token const token = localStorage.getItem('token') if (token) { modifiedRequest.headers.append('Authorization', `Bearer ${token}`) } // 发送修改后的请求 event.respondWith(fetch(modifiedRequest)) } else { // 其他请求直接放行 event.respondWith(fetch(request)) } })
方案三:后端生成带签名的临时访问URL(推荐,通用型强)
在DRF后端写一个视图,生成带签名的临时视频URL,前端拿到这个URL后直接给videojs使用,无需携带认证头,URL在有效期内可访问,过期自动失效。
- DRF后端视图示例:
from django.core.signing import TimestampSigner from django.http import HttpResponseRedirect from rest_framework.views import APIView from rest_framework.permissions import IsAuthenticated class VideoTempURLView(APIView): permission_classes = [IsAuthenticated] def get(self, request, video_id): # 生成带时间戳的签名,设置有效期为1小时(3600秒) signer = TimestampSigner() signed_data = signer.sign(f'video_{video_id}') # 生成临时URL,假设视频文件实际路径是/media/videos/{video_id}.mp4 temp_url = f'/media/videos/{video_id}.mp4?sig={signed_data}' return HttpResponseRedirect(temp_url)
- 后端签名验证中间件:
from django.core.signing import TimestampSigner, BadSignature, SignatureExpired from django.http import HttpResponseForbidden def validate_video_signature(get_response): def middleware(request): if request.path.startswith('/media/videos/') and 'sig' in request.GET: sig = request.GET.get('sig') signer = TimestampSigner() try: # 验证签名,有效期1小时 data = signer.unsign(sig, max_age=3600) # 可添加视频存在性验证逻辑,比如根据data中的video_id查询数据库 except (BadSignature, SignatureExpired): return HttpResponseForbidden('无效或过期的访问链接') return get_response(request) return middleware
- 前端调用示例:
<template> <video-player :options="playerOptions"></video-player> </template> <script> import axios from 'axios' import VideoPlayer from '@videojs-player/vue' export default { components: { VideoPlayer }, data() { return { playerOptions: { sources: [] } } }, async mounted() { try { // 请求后端临时URL接口 const response = await axios.get('/api/video-temp-url/1/') // 取重定向后的临时URL const tempUrl = response.request.responseURL this.playerOptions.sources = [{ src: tempUrl, type: 'video/mp4' }] } catch (err) { console.error('获取临时视频链接失败:', err) } } } </script>
内容的提问来源于stack exchange,提问作者Samuele B.
相关产品推荐
相关产品推荐

