前言
- 現(xiàn)在許多視頻在線觀看網(wǎng)站,你如果打開chrome查看其video標(biāo)簽妒挎,會(huì)發(fā)現(xiàn)它的src是一個(gè)以
blob:
開頭的地址四瘫。比如下面這里是B站的截圖八孝,可以看到他這里引入的并不是一個(gè)在線的視頻存放地址,這樣你通過爬蟲腳本也無法下載該視頻文件应役,通過一個(gè)new tab打開也于事無補(bǔ)情组,會(huì)提示你地址錯(cuò)誤。
createObjectURL與BLOB
- 我們?cè)倩氐侥莻€(gè)以
blob:
開頭的神秘字符串箩祥,它其實(shí)是通過URL.createObjectURL
這個(gè)API生成的院崇,該函數(shù)接收一個(gè)BLOB對(duì)象,返回該對(duì)象對(duì)應(yīng)的DOMString
袍祖,這個(gè)字符串其實(shí)也可以看做是一個(gè)url地址底瓣,但它是與當(dāng)前窗口的document
對(duì)象綁定的,也可以說是會(huì)話(session)級(jí)的,所以你在新的tab打開也就無效了
- 再來了解下BLOB捐凭,他的全稱為big binary large object拨扶,二進(jìn)制大對(duì)象。如果把一個(gè)視頻文件轉(zhuǎn)換成二進(jìn)制對(duì)象茁肠,其大小肯定很大患民,這樣理解就清楚多了。在瀏覽器端也提供了BLOB相關(guān)的API垦梆,通過
new Blog(...)
生成blog對(duì)象匹颤。
- 拿到blog對(duì)象后,再通過
URL.createObjectURL
生成臨時(shí)地址托猩,賦值給video標(biāo)簽的src屬性印蓖,這樣就可以了。但其實(shí)可以直接從服務(wù)端接收二進(jìn)制對(duì)象京腥,就是服務(wù)端把視頻文件轉(zhuǎn)換成二進(jìn)制對(duì)象赦肃,通過接口給到前端,前端再生成dom string
公浪。
代碼實(shí)現(xiàn)
- 服務(wù)端使用的nodejs他宛,koa框架,這里的操作很簡(jiǎn)單欠气,就是用
fs.readFileSync
直接打開視頻文件堕汞,得到的data結(jié)果是二進(jìn)制的數(shù)據(jù),直接作為結(jié)果返回晃琳。
const Koa = require('koa')
const Router = require('koa-router')
const buffer = require('buffer');
const app = new Koa()
const router = new Router()
const fs = require('fs')
const video = async (ctx, next) => {
try {
// open 一個(gè)放在服務(wù)器的視頻
let data = fs.readFileSync('XXX.XXX.XXX/simple.mp4')
ctx.response.body = data
} catch (e) {
return Promise.reject({
status: 500,
message: '視頻傳輸錯(cuò)誤'
})
}
next()
}
router.get('/video', video)
app.use(router.routes()).use(router.allowedMethods())
app.listen(3001)
- 接下來看前端代碼,這里使用的最原生的
XMLHttpRequest
對(duì)象語法琐鲁,這里最重要的一點(diǎn)是要設(shè)置responseType為blob卫旱,這樣接收到response直接就是一個(gè)blob對(duì)象供我們使用。這個(gè)responseType屬性不屬于http頭部信息围段,而是ajax請(qǐng)求中XHR對(duì)象的屬性(默認(rèn)為""也就是text
類型顾翼,而在一些封裝XHR的框架中,一般把默認(rèn)值設(shè)為json
)奈泪。
let xhr = new XMLHttpRequest()
xhr.open('GET', 'http://localhost:3001/video', true)
xhr.responseType = 'blob'
xhr.onload = function(e) {
if (this.status === 200) {
// 獲取blob對(duì)象
let blob = this.response
console.log(blob)
// 獲取blob對(duì)象地址适贸,并把值賦給容器
$("#sound").attr("src", URL.createObjectURL(blob));
}
}
xhr.send()
- 這樣就可以得到以
blob:
開頭的臨時(shí)url地址,而且在向服務(wù)端請(qǐng)求時(shí)頁隱藏了真實(shí)的視頻地址涝桅。