问题
I am implementing HTTP2/SPDY push resourcing using the node module spdy. I have followed indutny's doc and have been doing test runs implementing his example into my server.js.
The problem is two fold; I am not getting any errors in the log(s) nor am I seeing the alert
in the browser. I don't see any change in the Developers Console as well. If I set a bogus push URL, I get no response/errors,etc. I believe in theory, the Priority should change from medium
to High
(?). See Screen shoot.
Is there another way for me to test if the push is being made to the browser? Or, do I have something wrong in my script (Please check for inconsistencies)? Also, what to throw in stream.on('error', function() {});
?
Testing in Chrome (on a ChromeBook), nodejs v5.1.0, npm v3.3.12 - H2 enabled is verified in Chrome.
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,
});
}
UPDATE: I have also added:
stream.on('acknowledge', function() {
console.log('stream ACK');
});
There is no console log written - It's like the function is dead.
Dev Console with push-stream (main.js):
回答1:
There are a few problems here.
The buffet callback is only invoked when the requested URL does not match a file on disk. Just like express middleware, it's essentially a
next
function. Thus, you're never actually pushing anything.The first argument to
res.push
is a URL, not a filesystem path.res.push
will not exist on ≤ HTTP/1.1 connections; you need to make sure it's there or you'll throw an uncaught exception (and crash).
Here's a reduced working example.
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);
As far as actually verifying in Chrome that things are being pushed, open a new tab and type chrome://net-internals/#http2
. Click the ID of the HTTP/2 session with your server, then click the session in the left-hand pane. Mixed in with the initial request, you'll see something like:
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"
(I did not see the Priority of main.js change in the dev tools -- it was still Medium.)
回答2:
Within the Chrome inspector, I discovered it is quite easily recognized when a resource has been pushed by the server.
First: Within the network view/tab, the resource(s) in question will show virtually no request
sent and 'waiting(TTFB)' in the waterfall (See image below).
The theme.min.css
& theme.min.js
resources are pushed:
Second: After clicking on the pushed the resource(s), opening the "Headers" pane and inspecting the "Request Headers" panel at the bottom, check for Provisional headers are shown
. If the warning is shown for the resource, then it was pushed. See this SO answer to why you will see this warning.
Headers Inspector:
If you need a little more detailed information about the pushed resource(s), using the chrome://net-internals/#http2
method as stated in the second part of @josh3736 answer would work too. But if you need a quick way to verify that the resource(s) has been pushed and excepted by the client, viewing the waterfall will show this.
来源:https://stackoverflow.com/questions/34049872/http2-spdy-push-stream-verification-how-to-test