HTTP2 / SPDY Push-Stream验证:如何测试?

时间:2015-12-02 18:05:35

标签: node.js spdy http2 pushstream

我正在使用节点模块spdy实施HTTP2 / SPDY推送资源。我已经关注indutny's doc并且已经在我的server.js中执行测试运行实例。

问题有两个; 我没有在日志中收到任何错误,也没有在浏览器中看到alert。我也没有在Developers Console中看到任何变化。如果我设置了虚假推送URL,我没有得到任何响应/错误等。我相信理论上,优先级应该从medium更改为High(?)。 See Screen shoot.

我是否有另一种方法可以测试是否对浏览器进行了推送?或者,我的脚本中是否有问题(请检查不一致)?还有什么要投入stream.on('error', function() {});

在Chrome中验证Chrome(在ChromeBook上),nodejs v5.1.0,npm v3.3.12 - 已启用H2。

server.js:

var environment = '../env/' + process.env.NODE_ENV
    // Process User config
  , fS = require('fs')
  , jsonFile = fS.readFileSync(environment + '/config.json')
  , jsonString, hostIp, hostPort, cacheExp, cps;

    try {
      jsonString              = JSON.parse(jsonFile);
      var SERV_HOST           = jsonString['hostIp']
        , SERV_PORT           = jsonString['hostPort']
        , CACHE_EXP           = jsonString['cacheExp']
        , CPS                 = jsonString['cps']
        , xPowerBy            = 'OceanPress'
        , xFrameOptions       = 'DENY'
        , xXSSProtection      = '1; mode=block'
        , xContentTypeOption  = 'nosniff';
    } catch (err) {
      console.log('There is an error parsing the json file : ' + err);
    }

// Load modules
var fs          = require('fs')
  , watch       = require('staticsmith-watch')
  , buffet      = require('buffet')({root: environment + '/_public'})
  , spdy        = require('spdy')
    // spdy options
  , options = {
      key: fs.readFileSync(environment + '/keys/key.pem')
    , cert: fs.readFileSync(environment + '/keys/cert.pem')
    // SPDY-specific options
    , spdy: {
          protocols: [ 'h2','spdy/3.1', 'spdy/3', 'spdy/2','http/1.1', 'http/1.0' ]
        , plain: false
        , maxStreams: 200
        , connection: {
              windowSize: 1024 * 1024
            , autoSpdy31: false
          }
      }
      // Set ip and port
    , host:   SERV_HOST
    , port:   SERV_PORT
  }
    // Security header options
  , security  = [
      { name:   'X-Powered-By',
        option: xPowerBy }
    , { name:   'x-frame-options',
        option: xFrameOptions }
    , { name:   'X-XSS-Protection',
        option: xXSSProtection }
    , { name:   'X-Content-Type-Options',
        option: xContentTypeOption }
    , { name:   'Cache-Control',
        option: CACHE_EXP }
    , { name:   'Content-Security-Policy',
        option: CPS }
    , { name:   'server',
        option: 'Who knows' }
  ];

if (process.env.NODE_ENV == 'production') {

  spdy.createServer(options, function(req, res) {

    // Add Content Security Rules
    for(var i = 0; i < security.length; i++) {
      res.setHeader(security[i].name, security[i].option);
    }

    // @see https://www.npmjs.com/package/buffet
    buffet(req, res, function (err, result) {

      // Push JavaScript asset (main.js) to the client
      var stream = res.push('/js/main.js', {
        req: {'accept': '*/*'},
        res: {'content-type': 'application/javascript'}
      });
      stream.on('acknowledge', function() {
          console.log("Stream ACK");
      });
      stream.on('error', function() {
        console.error("stream ERR");
      });
      stream.end('alert("hello from push stream!");');
      // write main response body and terminate stream
      res.end('<script src="/js/main.js"></script>');

      // There was an error serving the file? Throw it!
      if (err) {
        console.error("Error serving " + req.url + " - " + err.message);
        // Respond to the client
        res.writeHead(err.status, err.headers);
      }
    });
  }).listen(options.port, options.host);

  console.log("serving at https://" + options.host + ":" + options.port);
  console.log("On Node v" + process.versions.node);
  console.log("On npm v" + process.versions.npm);

  watch({
    pattern:    '**/*',
    livereload: true,
  });
}

更新 我还补充说:

  stream.on('acknowledge', function() {
      console.log('stream ACK');
  });

没有写入控制台日志 - 就像函数已经死了一样。

具有推送流的开发者控制台(main.js):
Dev Console with push-stream (main.js)

2 个答案:

答案 0 :(得分:2)

这里有一些问题。

  1. 仅当请求的网址与磁盘上的文件匹配时,才会调用自助回调。就像快速中间件一样,它本质上是一个next函数。因此,你实际上从来没有推过任何东西。

  2. res.push的第一个参数是一个URL,而不是一个文件系统路径。

  3. res.push将不存在于≤HTTP/ 1.1连接上;你需要确保它在那里,否则你将抛出未被捕获的异常(并崩溃)。

  4. 这是一个简化的工作示例。

    spdy.createServer({
        key: fs.readFileSync('./s.key'),
        cert: fs.readFileSync('./s.crt')
    }, function(req, res) {
    
        if (req.url == '/') {
            res.writeHead(200, { 'Content-Length': 42 });
            res.end('<h1>Hi</h1><script src="main.js"></script>');
    
            if (res.push) {
    
                // Push JavaScript asset (main.js) to the client
                var stream = res.push('/main.js', {
                    req: {'accept': '**/*'},
                    res: {'content-type': 'application/javascript'}
                });
    
                stream.on('error', function() {
                    console.error(err);
                });
                stream.end('alert("hello from push stream!");');
            }
        } else {
            res.writeHead(404);
            res.end();
        }
    
    
    
    }).listen(777);
    

    至于在Chrome中实际验证是否正在推送内容,请打开新标签页并输入chrome://net-internals/#http2。单击与服务器的HTTP / 2会话的ID,然后单击左侧窗格中的会话。与初始请求混在一起,你会看到类似的东西:

    t=  3483 [st=    19]  HTTP2_SESSION_RECV_PUSH_PROMISE
                          --> :method: GET
                              :path: /main.js
                              :scheme: https
                              :authority: localhost:777
                          --> id = 3
                          --> promised_stream_id = 4
    t=  3483 [st=    19]  HTTP2_SESSION_RECV_HEADERS
                          --> fin = false
                          --> :status: 200
                          --> stream_id = 4
    t=  3483 [st=    19]  HTTP2_SESSION_RECV_DATA
                          --> fin = true
                          --> size = 0
                          --> stream_id = 4
    t=  3546 [st=    82]  HTTP2_STREAM_ADOPTED_PUSH_STREAM
                          --> stream_id = 4
                          --> url = "https://localhost:777/main.js"
    

    (我没有看到开发工具中main.js的优先级发生变化 - 它仍然是中等。)

答案 1 :(得分:0)

在Chrome检查器中,我发现当服务器推送资源时很容易识别它。

首先:在网络视图/标签中,相关资源在瀑布中几乎不会显示request已发送和'等待(TTFB)'(见下图)。

theme.min.css&amp;推送theme.min.js资源:

enter image description here

第二:点击推送资源后,打开“标题”窗格并检查底部的“请求标题”面板,检查Provisional headers are shown。如果显示资源的警告,则推送它。 See this SO answer为什么你会看到这个警告。

标题检查员:

enter image description here

如果您需要有关推送资源的更详细信息,请使用@josh3736 answer第二部分中所述的chrome://net-internals/#http2方法。但是,如果您需要快速验证资源是否已被客户端推送和排除,则查看瀑布将显示此信息。