前言
- 現在許多視頻在線觀看網站,你如果打開chrome查看其video標簽,會發現它的src是一個以
blob:
開頭的地址。比如下面這里是B站的截圖,可以看到他這里引入的并不是一個在線的視頻存放地址,這樣你通過爬蟲腳本也無法下載該視頻文件,通過一個new tab打開也于事無補,會提示你地址錯誤。
createObjectURL與BLOB
- 我們再回到那個以
blob:
開頭的神秘字符串,它其實是通過URL.createObjectURL
這個API生成的,該函數接收一個BLOB對象,返回該對象對應的DOMString
,這個字符串其實也可以看做是一個url地址,但它是與當前窗口的document
對象綁定的,也可以說是會話(session)級的,所以你在新的tab打開也就無效了
- 再來了解下BLOB,他的全稱為big binary large object,二進制大對象。如果把一個視頻文件轉換成二進制對象,其大小肯定很大,這樣理解就清楚多了。在瀏覽器端也提供了BLOB相關的API,通過
new Blog(...)
生成blog對象。
- 拿到blog對象后,再通過
URL.createObjectURL
生成臨時地址,賦值給video標簽的src屬性,這樣就可以了。但其實可以直接從服務端接收二進制對象,就是服務端把視頻文件轉換成二進制對象,通過接口給到前端,前端再生成dom string
。
代碼實現
- 服務端使用的nodejs,koa框架,這里的操作很簡單,就是用
fs.readFileSync
直接打開視頻文件,得到的data結果是二進制的數據,直接作為結果返回。
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 一個放在服務器的視頻
let data = fs.readFileSync('XXX.XXX.XXX/simple.mp4')
ctx.response.body = data
} catch (e) {
return Promise.reject({
status: 500,
message: '視頻傳輸錯誤'
})
}
next()
}
router.get('/video', video)
app.use(router.routes()).use(router.allowedMethods())
app.listen(3001)
- 接下來看前端代碼,這里使用的最原生的
XMLHttpRequest
對象語法,這里最重要的一點是要設置responseType為blob,這樣接收到response直接就是一個blob對象供我們使用。這個responseType屬性不屬于http頭部信息,而是ajax請求中XHR對象的屬性(默認為""也就是text
類型,而在一些封裝XHR的框架中,一般把默認值設為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對象
let blob = this.response
console.log(blob)
// 獲取blob對象地址,并把值賦給容器
$("#sound").attr("src", URL.createObjectURL(blob));
}
}
xhr.send()
- 這樣就可以得到以
blob:
開頭的臨時url地址,而且在向服務端請求時頁隱藏了真實的視頻地址。