简体   繁体   中英

HTTP/2: stream.end using For-Loop

How can a stream be closed within a for-loop ?

I am attempting a HTTP/2 resource push-stream within a loop by reading a .json config file. If there is only one resource in the resurce.file,type , the push is successful. If there are more than one resource in the config, only the first resource listed is pushed and the remaining resource(s) are not pushed & the client never receives the remaining files and will not finish parsing.

I am thinking that only the first resource stream ends and the remaining open streams are not closing.

I commented as best as I believe the code should be functioning:

// Verify if client can be pushed to:
if (res.push) {

  // Read what resources should be pushed via config.json5:
  for(var i = 0; i < confg.resource.length; i++) {

    // Compare what URL requested the resources & pass the relevant files:
    if (req.url == confg.resource[i].url) {

      // Request the resource(s) to stream:
      var ps  = fs.readFileSync('../build' + confg.resource[i].file)

          // Push the relevant resource stream(s):
        , stream = res.push(confg.resource[i].file
        , { // ..and set the content type;
            res: {'content-type': confg.resource[i].type},
          });

      // Close the resource stream(s):
      stream.end(ps, function() {
        // TODO(CelticParser): Remove for production ->v
        console.log("Pushed Sream");
      });
    }
  }
}

.config.json5:

resource: [ // HTTP/2 Push-Streams
  { file: '/js/theme.min.js',
     type: 'script'
  },
  { file: '/css/theme.min.css',
    type: 'style',
    url:  '/'
  }
]

Using the example above;

If the /js/theme.min.js is listed first and the /css/theme.min.css is listed second in the config , the /js/theme.min.js will be loaded by the browser and the other file will not load and the client hangs up ( doesn't continue parsing ). If the the list order of the resources are swapped, the same thing occurs. If there is only one file listed in the config, everything works as expected.

Any help will be greatly appreciated.

The problem is in config.json5 . You are checking the requested url before passing the files here:

// Compare what URL requested the resources & pass the relevant files:
if (req.url == confg.resource[i].url) {
   ...
}

But in your json only one item can pass the test, the other one is missing the url property. Change your config to this (added url: '/' to the first item) and it will work:

{
   resource : [
      { 
         file : '/js/theme.min.js',
         type : 'script',
         url  :  '/'
      },
      { 
         file : '/css/theme.min.css',
         type : 'style',
         url  :  '/'
      }
   ]
}

Tested with this small app, following the http2 server example , and also with your server code.

server.js

var fs      = require("fs");
var path    = require("path");
var http2   = require("http2");
var config  = require("./config.json");

var options = {
    key  : fs.readFileSync("./localhost.key"),
    cert : fs.readFileSync("./localhost.crt")
};

//----------------------------------------------------
http2.createServer(options, function(req, res) {

    if (res.push) {

        config.resource.forEach(function(resource){

            if (req.url === resource.url) {

                var push = res.push(resource.file, { res: {"content-type": resource.type } });
                push.writeHead(200);
                fs.createReadStream(path.join("../build", resource.file)).pipe(push);
            }
        });
    }

    res.writeHead(200);
    res.end();

}).listen(8080);

The config.json file contains the corrected config described above.

Output :

Receiving pushed resource: ./js/bootstrap.min.js -> /Developer/so/tests/push-0
Receiving pushed resource: ./css/bootstrap.min.css -> /Developer/so/tests/push-1

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM