I have been developing this site: https://mirobod-tumani.vercel.app. On the home page there is a video background. To optimize the initial load, i optimized the video itself and decided to stream it. This is the code:
// pages/api/video
import fs from 'fs'
export default function handler(req, res) {
if (req.method === 'GET') {
const range = req.headers.range
const videoPath = 'public/assets/mirobod.webm'
const videoSize = fs.statSync(videoPath).size
const chunkSize = 1 * 1e6
const start = Number(range.replace(/\D/g, ''))
const end = Math.min(start + chunkSize, videoSize - 1)
const contentLength = end - start + 1
const headers = {
'Content-Range': `bytes ${start}-${end}/${videoSize}`,
'Accept-Ranges': 'bytes',
'Content-Length': contentLength,
'Content-Type': 'video/webm',
}
res.writeHead(206, headers)
const stream = fs.createReadStream(videoPath, { start, end })
stream.pipe(res)
}
// pages/index.js
<video autoPlay muted loop>
<source src='/api/video' type='video/webm' />
</video>
Locally, when i navigate to root localhost:3000/
it is working as i expect,
but when i try to open that /api/video
api differently, for example, when i navigate to localhost:3000/api/video
or call it in Postman, there is an error saying Cannot read property 'replace' of undefined
, i undestand that req.headers.range
is undefined
. Also in production there is a 500 error with that api and not showing the video as you can see from the site link above.
I tried:
if(!req.headers.range) // send the whole video at one
else ...
But in this case, this is not what i want from streaming and also this leads Exceeding Serverless Function Payload Size Limit
So what is the problem, what should i do? Thank you in advance!
I found an answer, posting it for anyone having the same issue.
For what i understood by this https://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.27
req.headers.range
may be not set for the initial request and be available during stream goes.
Actually, initial range is equal to 'bytes=0-', and updates during the stream depending on your defined chunk size
So it did:
let range = req.headers.range
if(!range) range = 'bytes=0-'
...
But there still was a problem I thought it was about the path, then i changed this:
const videoPath = 'public/assets/mirobod.webm'
to this:
const videoName = 'mirobod.webm'
const videoPath = path.resolve('public/assets/', videoName)
And it succeeded!