過去,構建視頻應用程序十分困難。在錄制、編碼和播放視頻背后有許多復雜的技術。幸運的是,Cloudflare Stream分擔走了所有困難的部分,現(xiàn)在您可以輕松構建自定義視頻和流媒體應用程序。讓我們看一下,我們可以如何結合Cloudflare Stream、Access、Pages和Workers,使用極少的代碼創(chuàng)建一個高性能的視頻應用程序。
今天,我們將構建一個受Cloudflare TV啟發(fā)的視頻應用程序。我們將提供用戶身份驗證,管理員可以上傳錄制的視頻或直播新內(nèi)容。能夠使用Cloudflare服務打造自己的YouTube或Twich,這多么令人興奮!
提取視頻列表
我們想要在應用程序主頁顯示所有視頻的列表,使用Cloudflare Stream上傳和存儲的所有視頻,之后還會有更多功能!該代碼可以更改,以僅顯示“熱門”視頻或為每個用戶選擇的視頻精選。目前,我們將使用搜索API并在一個空字符串中傳遞以返回全部。
import { getSignedStreamId } from "../../src/cfStream"
export async function onRequestGet(context) {
const {
request,
env,
params,
} = context
const { id } = params
if (id) {
const res = await fetch(`https://api.cloudflare.com/client/v4/accounts/${env.CF_ACCOUNT_ID}/stream/${id}`, {
method: "GET",
headers: {
"Authorization": `Bearer ${env.CF_API_TOKEN_STREAM}`
}
})
const video = (await res.json()).result
if (video.meta.visibility !== "public") {
return new Response(null, {status: 401})
}
const signedId = await getSignedStreamId(id, env.CF_STREAM_SIGNING_KEY)
return new Response(JSON.stringify({
signedId: `${signedId}`
}), {
headers: {
"content-type": "application/json"
}
})
} else {
const url = new URL(request.url)
const res = await (await fetch(`https://api.cloudflare.com/client/v4/accounts/${env.CF_ACCOUNT_ID}/stream?search=${url.searchParams.get("search") || ""}`, {
headers: {
"Authorization": `Bearer ${env.CF_API_TOKEN_STREAM}`
}
})).json()
const filteredVideos = res.result.filter(x => x.meta.visibility === "public")
const videos = await Promise.all(filteredVideos.map(async x => {
const signedId = await getSignedStreamId(x.uid, env.CF_STREAM_SIGNING_KEY)
return {
uid: x.uid,
status: x.status,
thumbnail: `https://videodelivery.net/${signedId}/thumbnails/thumbnail.jpg`,
meta: {
name: x.meta.name
},
created: x.created,
modified: x.modified,
duration: x.duration,
}
}))
return new Response(JSON.stringify(videos), {headers: {"content-type": "application/json"}})
}
}
我們將仔細檢查每個視頻,過濾掉任何私人視頻,并抽取出我們需要的元數(shù)據(jù),例如縮略圖URL、ID和創(chuàng)建日期。
播放視頻
要允許用戶從我們的應用程序播放視頻,則需要公開視頻,否則您將需要簽署每個請求。將視頻標記為“公開”可使整個過程更為簡單。然而,可能出于許多原因,您想要控制對視頻的訪問。如果您希望用戶登錄后才可播放視頻,或者想要能夠以任何方式限制訪問,可將視頻標記為“私人”并使用簽名的URL來控制訪問。
如果您在本地測試您的應用程序,或希望每天的請求數(shù)少于10,000個,您可以調用/token端點以生成一個簽名令牌。如果您希望每天超過10,000個請求,請使用JSON Web Tokens簽署您自己的令牌,就像我們這里所做的一樣。
允許用戶上傳視頻
下一步是構建管理員頁面,用戶可在其中上傳他們的視頻。
Cloudflare Stream API使該過程得到了簡化。您可使用您的API令牌和帳戶ID生成一個唯一的一次性上傳URL。僅需確保您的令牌擁有Stream:Edit權限即可。我們從應用程序鉤入所有POST請求,并返回生成的上傳URL。
export const cfTeamsAccessAuthMiddleware = async ({request, data, env, next}) => {
try {
const userEmail = request.headers.get("cf-access-authenticated-user-email")
if (!userEmail) {
throw new Error("User not found, make sure application is behind Cloudflare Access")
}
// Pass user info to next handlers
data.user = {
email: userEmail
}
return next()
} catch (e) {
return new Response(e.toString(), {status: 401})
}
}
export const onRequest = [
cfTeamsAccessAuthMiddleware
]
管理員頁面包含一個表單,允許用戶從他們的計算機拖放或上傳視頻。當一個已登錄用戶點擊上傳表單上的“提交”時,應用程序會生成一個唯一的URL,然后向其發(fā)布FormData。該代碼可有效用于構建視頻分享網(wǎng)站或與任何允許用戶生成內(nèi)容的應用程序搭配使用。
async function getOneTimeUploadUrl() {
const res = await fetch('/api/admin/videos', {method: 'POST', headers: {'accept': 'application/json'}})
const upload = await res.json()
return upload.uploadURL
}
async function uploadVideo() {
const videoInput = document.getElementById("video");
const oneTimeUploadUrl = await getOneTimeUploadUrl();
const video = videoInput.files[0];
const formData = new FormData();
formData.append("file", video);
const uploadResult = await fetch(oneTimeUploadUrl, {
method: "POST",
body: formData,
})
}
使用Stream Live添加實時視頻
您還可以使用Stream Live,結合我們已經(jīng)討論過的技術,向您的應用程序添加直播部分。您可以允許已登錄用戶開始直播,并允許其他已登錄用戶(甚至是未登錄用戶)實時觀看!直播內(nèi)容將自動保存至您的帳戶,因此,當直播結束后就可以立即在應用程序的主要區(qū)域查看直播內(nèi)容。
使用中間件保護我們的應用程序
我們將所有經(jīng)過身份驗證的頁面都放在此中間件函數(shù)后方。它會檢查請求標頭以確保用戶正在發(fā)送有效的經(jīng)過身份驗證的用戶電子郵件。
export const cfTeamsAccessAuthMiddleware = async ({request, data, env, next}) => {
try {
const userEmail = request.headers.get("cf-access-authenticated-user-email")
if (!userEmail) {
throw new Error("User not found, make sure application is behind Cloudflare Access")
}
// Pass user info to next handlers
data.user = {
email: userEmail
}
return next()
} catch (e) {
return new Response(e.toString(), {status: 401})
}
}
export const onRequest = [
cfTeamsAccessAuthMiddleware
]
使用Pages將所有功能組合起來
我們使用Cloudflare Access來控制我們的登錄流程,使用Stream API管理上傳、顯示和觀看視頻,使用Workers來管理fetch請求和處理API調用。現(xiàn)在,讓我們使用Cloudflare Pages將所有功能結合起來!
Pages提供一種簡單的方法來部署和托管靜態(tài)網(wǎng)站。不過現(xiàn)在,Pages可與Workers平臺無縫集成(公告文章鏈接)。使用該新集成,我們可以使用單個可讀存儲庫來部署這一整個應用程序。
控制訪問
一些應用程序更適合公開;另一些應用程序包含敏感數(shù)據(jù),應當限制向特定用戶開放。此應用程序的主頁是公開的,我們已使用Cloudflare Access將管理員頁面限制為僅向員工開放。如果您要構建內(nèi)部學習服務,甚至想要推出新網(wǎng)站的測試版,您都可以輕松使用Access保護您的整個應用程序!
當用戶點擊我們演示網(wǎng)站上的管理員鏈接時,將提示他們輸入電子郵件地址。如果他們輸入有效的Cloudflare電子郵件,則應用程序會向他們發(fā)送訪問代碼。否則,他們將無法訪問該頁面。