user3454321
user3454321

Reputation:

Node JS Request + Express Pipe

I have a problem with streaming video files from a server to another.

I wrote this script

var request = require("request"),
    express = require("express");

var app = express();

app.get("/cast", function(req, res) {

    var url = req.query.video;

    res.writeHead(200, {
        'Content-Type': 'video/mp4'
    });

    request({
        url: url,
        headers: {
            Referer: "http://example.com/1706398/" + url
        }
    })
        .on('response', function(response) {

            response.on('data', function(data) {
                console.log("data chunk received: " + data.length)
            });

            response.on('end', function(data) {
                console.log('Video completed');
            });

        })
        .pipe(res);

});

app.listen(8080);

But video response sometimes works sometimes is corrupted, instead if request's data is written in a writeable buffer and saved as video file it works with any url. I cannot found any error or problem in my code, here some urls :

Here some url that I tryed: https://gist.github.com/FrancisCan/f2bb86f8ff73b45fa192

Thanks :)

Upvotes: 1

Views: 4158

Answers (1)

Luis Delgado
Luis Delgado

Reputation: 3734

Remove the writeHead 200, when you are streaming, you should return http 206 results back (partial content), and not http200. I have the same scenario as you (streaming a video file from a blob container in the cloud to an angular application), there is no need for the http200 response.

Update: adding some code on how I do it:

AzureStorageHelper.prototype.streamBlob = function streamBlob(req, res, blob, params) {
    if(!params){
        params.container = container;
    }
    blob_service.getBlobProperties(params.container, blob, function (error, result, response) {
        if(!result) return res.status(404).end();
        if(error) return res.status(500).end();

        var blobLength = result.contentLength;
        var range = req.headers.range ? req.headers.range : "bytes=0-";
        var positions = range.replace(/bytes=/, "").split("-");
        var start = parseInt(positions[0], 10);
        var end = positions[1] ? parseInt(positions[1], 10) : blobLength - 1;
        var chunksize = (end - start) + 1;
        var options = {
            rangeStart: start,
            rangeEnd: end,
        }

        //this is what's interesting for your scenario. I used to set this up myself but it's is now handled by the Azure Storage NodejsSDK

        /*res.writeHead(206, {
            'Accept-Ranges': 'bytes',
            'Content-Range': "bytes " + start + "-" + end + "/" + blobLength,
            'Content-Type': result.contentType,
            'Content-Length': chunksize,
            'Content-MD5': result.contentMD5,
        });*/

        var options = {
            rangeStart: start,
            rangeEnd: end,
        }

//this is an API from the Azure Storage nodejsSDK I use. You might want to check the source of this method in github to see how this lib deals with the http206 responses and the piping
        blob_service.getBlobToStream(params.container, blob, res, options, function (error, result, response) {
            if (error) {
                return res.status(500).end();
            }
        });
    });

Upvotes: 2

Related Questions