Tuesday, April 17, 2012

Edge Node-SPDY and Express.js

‹prev | My Chain | next›

I am back on edge node-spdy and the view is wonderful. To be sure there are drawbacks suck as only running on edge node.js—but that is a also a benefit since edge node.js bundles a SPDY-friendly version of openssl. One of the other features of edge node-spdy is that it supports express.js out of the box. Tonight I am going to try to see how that works.

My first instinct is to install edge express.js (along with edge connect.js) in order to get this working:
➜  express-spdy-test  npm install ~/repos/express ~/repos/connect ~/repos/node-spdy
...
spdy@1.2.0 ./node_modules/spdy

express@3.0.0alpha1-pre ./node_modules/express
├── debug@0.6.0
├── commander@0.5.2
├── mime@1.2.5
└── mkdirp@0.3.0

connect@2.1.2 ./node_modules/connect
├── debug@0.6.0
├── qs@0.4.2
├── mime@1.2.4
├── formidable@1.0.9
└── crc@0.1.0
I am not 100% clear if this will work because express.js has changed in preparation for the 0.8 series of node.js. The new 3.0 series of express.js features, among other things, a server object created with the express() method rather than the current createServer(). I have no idea how deep such changes go. Breaking things is one way to find out...

I start with a modified version of a generated express.js app.js:
var express = require('express')
  , spdy = require('spdy')
  , fs = require('fs')
  , routes = require('./routes');

//var app = module.exports = express.createServer();
var app = spdy.createServer(express.HTTPSServer, {
  key: fs.readFileSync(__dirname + '/keys/spdy-key.pem'),
  cert: fs.readFileSync(__dirname + '/keys/spdy-cert.pem'),
  ca: fs.readFileSync(__dirname + '/keys/spdy-csr.pem')
});
I require express, spdy and a couple other necessary modules. Then I create an app server instance via node-spdys' createServer() constructor. The first argument passed into createServer() is the base class used to create the application server instance—node-spdy should just decorate this instance with a few tweaks of its own.

When I start the server up, however, I get:
➜  express-spdy-test  node app                             

node.js:247
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
Error: addListener only takes instances of Function
    at Server.<anonymous> (events.js:101:11)
    at Server.Server (https.js:38:10)
    at new Server (/home/chris/tmp/express-spdy-test/node_modules/spdy/lib/spdy/server.js:24:17)
    at Object.create [as createServer] (/home/chris/tmp/express-spdy-test/node_modules/spdy/lib/spdy/server.js:98:10)
    at Object.<anonymous> (/home/chris/tmp/express-spdy-test/app.js:12:16)
    ....
Hrm... that error is coming from node-spdy itself. Ah, after a bit of investigation, I realize that express.HTTPSServer is undefined in express 3.0.

Instead, I try passing in the other option suggested by the node-spdy documentation: https.Server:
var app = spdy.createServer(https.Server, {
  // ...
});
This changes the message, but still does not give me a SPDY-enabled express.js:
➜  express-spdy-test  node app

node.js:247
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
TypeError: Object #<Server> has no method 'configure'
    at Object.<anonymous> (/home/chris/tmp/express-spdy-test/app.js:22:5)
    ...
I would not expect https.Server to respond to configure(). That is an express.js method whereas https.Server comes from node.js core.

So I give up, for now, on trying to get this working with the 3.0 series of express.js. Instead, I switch my local fork of express.js back to the 2.x series. Specifically, my fork includes the provision that this will work with the unstable version of node.js in package.json:
{ 
  "name": "express",
  "description": "Sinatra inspired web development framework",
  "version": "2.5.9",
  "author": "TJ Holowaychuk ",
  // ....
  "engines": { "node": ">= 0.4.1 < 0.9.0" }
}
I re-install in my test application directory:
➜  express-spdy-test  npm install ~/repos/express ~/repos/connect ~/repos/node-spdy
And I change the app.js server to create express.HTTPSServer objects:
//var app = module.exports = express.createServer();
var app = spdy.createServer(express.HTTPSServer, {
  // ...
});
With that, I get the server to start up:
➜  express-spdy-test  node app
Express server listening on port 3000 in development mode
And a quick inspection of chrome://net-internals reveals that I do have a legitimate SPDY server.

Day #359

No comments:

Post a Comment