在之後的開發項目中,極可能有作在線視頻的,而在線視頻就有個問題,由於在線播放,就頗有可能視頻數據被抓包,若是這個在線視頻平臺有付費視頻的話,這樣就會有人作點倒賣視頻的生意了,針對這個問題,目前國內有不少不錯的加密視頻平臺,能夠把你平臺的視頻放在他們那裏,而後經過他們的機制進行加密,而後作一套機制,當用戶使用平臺播放時,實際上是平臺去加密視頻方請求過來的加密視頻,這樣就能夠保證視頻的安全性了php
鄙人據說的,有保利威,金盾,還有不少不少我叫不上名,搜索引擎一搜就有一大堆的,本次教程說的是保利威css
官網:傳送門 有直播和點播的服務,直播是什麼不用多說了吧,點播的意思就是我上面說的,把錄製好的視頻放到平臺那種html
本教程只介紹使用雲點播功能前端
點擊使用手冊的雲點播:使用手冊文檔:傳送門vue
選到h5視頻播放:固然你也可使用flash,可是如今的平臺基本都用的是h5了,因此本次選用h5的html5
複製這段代碼放到一個html文檔裏,直接點那個瀏覽器標識打開測試:ios
這個頁面整個都是保利威給我咱們提供的,能夠加速播放,能夠查看視頻參數,能夠看列表,而後還有個【test】這個就是跑馬燈,相信有過購買視頻的朋友都知道,你看你的付費視頻時,都有本身的用戶名啥的,假如你本身私自錄製,傳出去,就是用這個跑馬燈就能夠追蹤到你的,他官方給的實例就是這樣npm
但其實,由於我電腦裝了IDM工具,且它這個視頻只是展現,尚未真正的加密(看到後面的你就知道爲何沒有真正的加密了),因此個人IDM自動嗅探視頻地址django
且還支持持斷點播放json
可是這個因爲是案例,因此利用IDM直接就能夠下載,且播放時尚未水印:
好的,演示的視頻就是這樣了。
你須要註冊一個保利威的帳號,而後拿到id和secret,點設置 - API接口:
注意id和secretkey以及token,這裏的token有讀的和寫的,後期會用到
上傳一個測試的視頻,上傳的時候設置加密參數
把加密設置打開,而後下面的移動端加密按你本身的需求來,我這裏暫且不設置
相關的更多的視頻配置參數:傳送門
好的,我這裏開始上傳,我上傳了一首歌的MV:
上傳完以後平臺自動解碼,而後就會有一個視頻加密的id了:
轉碼以後,審覈:
在審覈的時候你就能夠作一些相關的視頻設置:
這裏還有不少的設置,不一一展現,本身體驗了
等待大概一兩分鐘以後,顯示已發佈,表示能夠用了:
這裏還有一些設置,好比播放域名設置,這些就本身去體驗了,我這裏這些都直接用默認的
看文檔得知有兩個步驟:
- 服務端獲取token,將token給客戶端
- 客戶端拿到token,開始播放視頻
他官方文檔給的是php的,不存在,後面重構成Python的就好了
播放有兩種播放形式,一種是直接在playsafe裏傳一個token,一種是給一個函數,函數必須帶視頻id和next,next是一個函數,在獲取token以後將token傳到next裏便可,而這官方給的文檔是next(playsafe),這裏有個坑,不是傳playsafe,而是傳token,我在這卡了好久
再次強調:視頻若是是加密的,須要設置加密參數 playsafe,playsafe有兩種形式,一個是傳token,一個是傳函數+next回調函數,且函數必須把token做爲值傳進去
下面還有更多的配置,切換視頻之類的,不一一展現了,本身研究
建立一個djangorestframework的項目,項目名爲EncryptVideo,app名爲app:
url:
polyv對象,在項目根目錄建立utils文件夾,該文件夾下建立polyv文件,定義一個Polyv對象
利用了設計模式裏的單例模式返回一個polyv_video對象
view:request.META.get('REMOTE_ADDR') 能夠獲取客戶端的IP地址 導入那個polyv對象
html,注意返回數據的層級,這個得根據你返回的數據來定
在這以前,我建議最好寫一個解決跨域請求的中間件,也放在utils目錄下:
啓動項目:Python manage.py runserver localhost:8000
那個html文件利用pycharm的功能從瀏覽器打開:
展現結果,朋友們,若是你遇到了這些坑,能夠按個人方法試試
第一個坑
(爲了避免浪費你們時間,我上面給的截圖其實已是我修改過而且正確的了)
發現返回的結果,sign params invild,意思就是說sign參數無效,那麼再看官方文檔:
sign的計算規則根本由這個concated生成的:
可是這句話,有歧義,按照ASCII升序拼接,究竟是先拼接了以後再按ASCII升序仍是先按ASCII升序以後再拼接,並且他這句,按照ASCKII升序 key + value + key + value ... +value 拼接,確實不知道到底怎麼拼接,因此我是這樣的:
固然你也能夠用列表生成式,反正怎麼舒服怎麼來,反正拼接順序就是先按key排序以後再key+value組合
第二個坑,這個坑我我的認爲操做的問題,其實不算坑,若是你遇到跟我同樣的問題,那恭喜你 嘻嘻
(上面的截圖也是正確的了,不浪費你們時間)
能夠顯示,可是點擊播放放不了,打開控制檯,報錯了:
(ip地址能夠忽略,這是我以前測試的時候遇到的問題 )
這個問題,我跟你說,看似是同源策略的問題,其實並非,就是我前面標註的那裏:
就是由於兩個url沒有統一致使的,因此必需要統一,要嘛都在結束符【/】,要嘛都不帶
第三個坑,錯誤的覺得保利威方給你報同源策略錯誤
(上面截圖也是已是正確的了)
展現結果仍是不能播放,而且連視頻縮略圖都沒了,並且如圖:
這個問題我是耗在這耗時最久的,報錯的意思就是跨域請求了,瀏覽器同源策略的問題,可是我把本地的啓動ip改爲了我局域網的ip【192.168.0.8:8000】,html部分axios異步請求那裏的也是【192.168.0.8:8000】,而後在django配置文件的這裏,我添加了這個
中間價對response的設置前面也設置了,啓動仍是不行,後面忽然醒悟過來,打印看token是否有拿到,確實有拿到
並且在咱們這個平臺,保利威,客戶三者之間的關係,實際上是這樣的:
也就是說,這個問題就是由於第2步以後的第3步上卡住,產生了跨域請求,因此這跟咱們沒多大關係了,是保利威視頻那邊的問題。前面這句話前半句是對的(「第2步以後的第3步上卡住了」),後面的分析都是錯的,可是當時的我不知道啊,按着錯誤的思路,我想了想,我在保利威後臺設置了一個視頻域名白名單:localhost:8000
有朋友回問,保利威那邊默認不就是對任何域名都沒有限制的嗎?是啊,可是我仍是設置了,設置以後,果真仍是不行,我還溯源,準備從這個next參數的開始:
我還去分析了他們的那個js文件,想找找next究竟是什麼:
發現簡直無從下手的。最後我就真的覺得是保利威那邊的問題域名問題,就是要設置那個域名才行,可是我這裏改下,那裏改下還成功了:
能夠播放了,能夠調播放速度啥的,注意,默認打開沒有聲,是由於默認音量按鈕沒開,本身點那個喇叭圖標打開音量
那按着這個錯誤的思路,有朋友會說,我設置域名是127.0.0.1:8000,把項目的啓動ip也啓動爲本地地址看看:
訪問:
因此仍是不能直接是ip地址。
可是!可是,根據個人經驗,我仍是不太放心,我又新建了一個django項目:
邏輯同樣,而後啓動的就是127.0.0.1:8001,而後保利威視頻域名限制我也刪了:
發現照樣能播放:
最後經個人研究發現,仍是獲取token那裏有問題,我把代碼從新寫的很是淺顯明瞭,什麼列表生成式的寫法都棄了,就爲了讀代碼順暢(上面的代碼截圖給的已是正確的了)
結果這樣確實能夠正常獲取token,而後next函數傳入token就直接播放了。
因此我錯誤的覺得保利威那邊的問題,饒了好久才發現。
以上是我我的的從分析問題,走錯分析的路掉進坑了,而後獲得的總結,若是大家沒有遇到,一鼓作氣,那麼你很棒,反正我是遇到了這些坑,最後不放心又測試了一次才找到根本問題的。固然以上都是我我的推斷,不表明絕對正確
好的,怎麼表明咱們真的配置好了呢?再上傳一個視頻,而後播放看看,若是真的沒問題,那之後就沒問題了,我開始上傳,並修改html上的id
瀏覽器打開:
相關代碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>保利威視頻測試</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script> </head> <body> <div id="player"></div> <script src="//player.polyv.net/script/player.js"></script> <script> var player = polyvPlayer({ wrap: '#player', width: 800, height: 533, vid: '2f57a436189b03930638e752c9a3761e_2', // 視頻id,對應帳號裏的視頻id playsafe: function (vid, next) { axios.request({ url: "http://localhost:8000/polyv", method: "POST", data: { vid: vid } }).then(function (data) { console.log(data.data); next(data.data.token); }) } }); </script> </body> </html>
from django.contrib import admin from django.urls import path from app.views import Polyv urlpatterns = [ path('admin/', admin.site.urls), path('polyv', Polyv.as_view()), # 這裏要與客戶端url對應,最後有沒有【/】要統一 ]
from django.conf import settings import time import requests import json import hashlib class PolyvPlayer(object): userId = settings.POLYV_CONFIG['userId'] secretkey = settings.POLYV_CONFIG['secretkey'] def tomd5(self, value): """取md5值""" return hashlib.md5(value.encode()).hexdigest() # 獲取視頻數據的token def get_video_token(self, videoId, viewerIp, viewerId=None, viewerName='', extraParams='HTML5'): """ :param videoId: 視頻id :param viewerId: 看視頻用戶id :param viewerIp: 看視頻用戶ip :param viewerName: 看視頻用戶暱稱 :param extraParams: 擴展參數 :param sign: 加密的sign :return: 返回點播的視頻的token """ ts = int(time.time() * 1000) # 時間戳 plain = { "userId": self.userId, 'videoId': videoId, 'ts': ts, 'viewerId': viewerId, 'viewerIp': viewerIp, 'viewerName': viewerName, 'extraParams': extraParams } # 按照官方文檔,將參數 按照ASCKII升序 key + value + key + value... + value 拼接 plain_sorted = {} key_temp = sorted(plain) for key in key_temp: plain_sorted[key] = plain[key] print(plain_sorted) plain_string = '' for k, v in plain_sorted.items(): plain_string += str(k) + str(v) print(plain_string) sign_data = self.secretkey + plain_string + self.secretkey # 取sign_data的md5的大寫 sign = self.tomd5(sign_data).upper() # 新的帶有sign的字典 plain.update({'sign': sign}) print('plain', plain) result = requests.post( url='https://hls.videocc.net/service/v1/token', headers={"Content-type": "application/x-www-form-urlencoded"}, # 必定要帶上這個請求頭 data=plain ).json() data = {} if isinstance(result, str) else result.get("data", {}) return {"token": data} polyv_video = PolyvPlayer()
from django.utils.deprecation import MiddlewareMixin class MyCorsMiddelware(MiddlewareMixin): def process_response(self, request, response): response["Access-Control-Allow-Origin"] = "*" if request.method == "OPTIONS": response["Access-Control-Allow-Headers"] = "*" return response
# --------- 保利威視頻註冊用戶id和key-------- POLYV_CONFIG = { 'userId': '您的id', # polyv 提供的服務器間的通信驗證 'secretkey': '您的secret' # polyv 提供的接口調用簽名訪問的key }
from django.shortcuts import render from rest_framework.views import APIView from rest_framework.response import Response from django.http import HttpResponse from utils.polyv import polyv_video import json class Polyv(APIView): def post(self, request): vid = request.data.get("vid") remote_addr = request.META.get("REMOTE_ADDR") user_id = 1 user_name = "test" verify_data = polyv_video.get_video_token(vid, remote_addr, user_id, user_name) return Response(verify_data["token"])
以上步驟其實已經能夠知足大部分用戶了,可是有朋友發現了,這裏仍是能夠用IDM直接下載啊:
因此接下來就要設置跑馬燈了
根據個人觀察,好像默認就開啓了跑馬燈的
這個地址能夠是本地的
這裏的域名部分,官方建議這樣設置,其實在後面我測試的時候,發現按照下面這個設置,兼容性很差,谷歌能夠播放,IE瀏覽器放不了
指向test_bolyv視圖函數
視圖函數:
這個get方法是保利威後臺自動調用的,不是咱們這邊服務端要用的,也不是客戶端要用的
user_name部分就是要顯示的跑馬燈數據
get_play_key和get_resp
get_play_key是獲取sign的,注意這裏的設置sign和上面獲取加密視頻的sign不太同樣
get_resp是作跑馬燈受權的:
這裏他給的例子是用的不加密的方式
咱們要播放加密視頻,固然仍是得使用playsafe參數播放,在templates目錄下新建一個tests.html,代碼以下,我標註出來的就是添加的參數,一樣的,注意返回數據的層級
啓動項目:
經過pycharm虛擬一個客戶端出來,點擊那些瀏覽器圖標打開,個人電腦是windows,因此試了谷歌,火狐和IE
谷歌:谷歌默認打開是沒有聲音的,這是谷歌瀏覽器的策略問題,不是大問題,正常播放,且正常顯示跑馬燈
IE:
再次強調,若是在那個xml文件裏,你若是按官方的建議設置成這樣:
而後你打開IE是播放不了的:
因此別按它建議的設置,就用默認的
火狐:
問題來了,就是這個問題,我折騰老久了,這個根本緣由仍是跨域請求問題,由於火狐瀏覽器默認安全性比較高,因此谷歌和IE能夠,就是火狐不行,我查閱了不少,好比關閉火狐的跨域請求的,設置跨域請求的,設置了不少,仍是沒用,最後使用了第三方庫django-cors-headers解決了,相關介紹安裝文章: 先後端分離djangorestframework——解決跨域請求 第5個方法
根據操做,重啓項目,火狐立馬播放:
而後如今你看我用IDM點下載:
我隨便選了一個:
提示:
最後再來個輔助測試,換個視頻id播放看看,換回這個視頻
火狐,谷歌,IE:
確實沒有問題了,這樣的操做是否是很6啊,我反正感受很6
詳細的參數配置步驟就沒展開了,具體看官方文檔吧:傳送門
相關代碼:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src='https://player.polyv.net/script/polyvplayer.min.js'></script> <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.js"></script> </head> <body> <div id="player"></div> <script> var player = polyvObject('#player').videoPlayer({ wrap: '#player', width: 800, height: 533, forceH5: true, vid: '2f57a43618b400b4f9c84fcea9b103a8_2', code: 'myRandomCodeValue', playsafe: function (vid, next) { // 向後端發送請求獲取加密的token console.log(vid); axios.request({ url: "http://localhost:8000/polyv", method: "POST", data: { vid: vid } }).then(function (data) { console.log(data); next(data.data.token) }) } }); </script> </body> </html>
<cross-domain-policy> <allow-access-from domain="*.polyv.net"/> </cross-domain-policy>
from django.conf import settings import time import requests import json import hashlib class PolyvPlayer(object): userId = settings.POLYV_CONFIG['userId'] secretkey = settings.POLYV_CONFIG['secretkey'] def tomd5(self, value): """取md5值""" return hashlib.md5(value.encode()).hexdigest() # 獲取視頻數據的token def get_video_token(self, videoId, viewerIp, viewerId=None, viewerName='', extraParams='HTML5'): """ :param videoId: 視頻id :param viewerId: 看視頻用戶id :param viewerIp: 看視頻用戶ip :param viewerName: 看視頻用戶暱稱 :param extraParams: 擴展參數 :param sign: 加密的sign :return: 返回點播的視頻的token """ ts = int(time.time() * 1000) # 時間戳 plain = { "userId": self.userId, 'videoId': videoId, 'ts': ts, 'viewerId': viewerId, 'viewerIp': viewerIp, 'viewerName': viewerName, 'extraParams': extraParams } # 按照官方文檔,將參數 按照ASCKII升序 key + value + key + value... + value 拼接 plain_sorted = {} key_temp = sorted(plain) for key in key_temp: plain_sorted[key] = plain[key] print(plain_sorted) plain_string = '' for k, v in plain_sorted.items(): plain_string += str(k) + str(v) print(plain_string) sign_data = self.secretkey + plain_string + self.secretkey # 取sign_data的md5的大寫 sign = self.tomd5(sign_data).upper() # 新的帶有sign的字典 plain.update({'sign': sign}) print('plain', plain) result = requests.post( url='https://hls.videocc.net/service/v1/token', headers={"Content-type": "application/x-www-form-urlencoded"}, # 必定要帶上這個請求頭 data=plain ).json() data = {} if isinstance(result, str) else result.get("data", {}) return {"token": data} def get_play_key(self, vid, username, code, status, ts): """ :param vid: 視頻 vid :param username: 響應跑馬燈展現 :param code: 自定義參數 :param status: 是否可播放, 一、可播放 二、禁播 :param ts: 時間戳 :return: 返回跑馬燈視頻的key """ return self.tomd5("vid={}&secretkey={}&username={}&code={}&status={}&t={}".format( vid, self.secretkey, username, code, status, ts)).lower() @staticmethod def get_resp(status, username, sign, msg="受權暫未經過"): res_str = { "status": status, "username": username, "sign": sign, "msg": msg, "fontSize": "18", "fontColor": "0xFF0000", "speed": "50", "filter": "on", "setting": "2", "alpha": "0.7", "filterAlpha": "1", "filterColor": "0x3914AF", "blurX": "2", "blurY": "2", "tweenTime": "1", "interval": "3", "lifeTime": "3", "strength": "4", "show": "on" } return res_str polyv_video = PolyvPlayer()
from django.shortcuts import render from rest_framework.views import APIView from rest_framework.response import Response from django.http import HttpResponse from utils.polyv import polyv_video import json class Polyv(APIView): def post(self, request): vid = request.data.get("vid") remote_addr = request.META.get("REMOTE_ADDR") user_id = 1 user_name = "test" verify_data = polyv_video.get_video_token(vid, remote_addr, user_id, user_name) return Response(verify_data["token"]) def get(self, request, *args, **kwargs): vid = request.query_params.get("vid", "") code = request.query_params.get("code", "") t = request.query_params.get("t", "") callback = request.query_params.get("callback", "") user_name = "test|1234565" status = 1 # username, code, status, t sign = polyv_video.get_play_key(vid, user_name, code, status, t) print(sign) res_str = polyv_video.get_resp(int(status), user_name, sign) res_str = json.dumps(res_str, ensure_ascii=False) if callback != "": ret = callback + "(" + res_str + ")" else: ret = res_str print(ret) return HttpResponse(ret) # 解決跨域 def test_bolyv(request): return render(request, "bolyv_test.html")
from django.contrib import admin from django.urls import path, re_path from app.views import test_bolyv from app.views import Polyv urlpatterns = [ path('admin/', admin.site.urls), path('polyv', Polyv.as_view()), # 這裏要與客戶端url對應,最後有沒有【/】要統一 re_path(r'^crossdomain.xml', test_bolyv) ]
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app.apps.AppConfig', 'corsheaders', ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'corsheaders.middleware.CorsMiddleware', 'django.middleware.common.CommonMiddleware', # 注意順序 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', # 'utils.middlewares.MyCorsMiddelware' # 這是咱們本身定義的那個中間件 ] # --------- 保利威視頻註冊用戶id和key-------- POLYV_CONFIG = { 'userId': '您的id', # polyv 提供的服務器間的通信驗證 'secretkey': '您的secret' # polyv 提供的接口調用簽名訪問的key } # 跨域增長忽略 CORS_ALLOW_CREDENTIALS = True CORS_ORIGIN_ALLOW_ALL = True CORS_ORIGIN_WHITELIST = ( '*' ) CORS_ALLOW_METHODS = ( 'DELETE', 'GET', 'OPTIONS', 'PATCH', 'POST', 'PUT', 'VIEW', ) CORS_ALLOW_HEADERS = ( 'XMLHttpRequest', 'X_FILENAME', 'accept-encoding', 'authorization', 'content-type', 'dnt', 'origin', 'user-agent', 'x-csrftoken', 'x-requested-with', )
- 通過這先後幾個接入第三方平臺的案例,發現其實都不算難,可是都有一些坑,必需要本身去實踐去研究了才能玩得會
- 火狐瀏覽器的安全級別默認很高,須要藉助第三方庫來配置
- 跑馬燈視頻設置get請求的url必須和主邏輯API接口是同一個
- 遇到問題仍是多研究,多理解,多分析