How to create an http2 node App

More Front End Technologies and Knowledge Points, Search Subscription Number JS Bacteria Subscription

  • All data is transported binary (sliced differently, HTTP2 was previously sent as a string)
  • Requests sent may be sent out of order
  • Efficient features such as header information compression and Server Push
  • Channel multiplexing (only one TCP link is required)
  • Frame-to-frame transmission (concurrent sending of different requests)

The benefits of using HTTP2 are not covered here anymore. A lot of materials on the web check themselves.

This short article briefly describes how to use http2 in node applications:

  • Require an SSL certificate first
  • Create Service-side APP
  • Install spdy module as an example of express

Self-signed SSL certificate

Generate Private Key

openssl genrsa -des3 -out server.key 2048

The above command uses the Triple-DES algorithm to generate the private key server.key

# cat server.key 

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,EB5B873BE89A5456

GWpEoVlP7DA9S955gUVZgrWww+PTspxwFMEoUKN9Z0WgjR30Qa+OOC93eyeVw/Zz
UvE60mCocTP0iSOOUCobW9i/v012zH6//QngqfzahVqqCz5B3zOAaB+LKOj/1S9X
GL7P7OOGWXik4nCGoN1rGszK6TqtboAl4YM00si/bU0wgrCxdCLV4ISvtMFV1cLz
4I0E9fbJI3MBZWlgTlm1RlOo0vyUFjmPJm78qLJlyD7Mk4VZ7uBh973UArkYpZNt
8hCtwj+DoPRUo/lXsoH4J/W3ma7BlrEjg7PkKffnX/L6HTqPMWV2zK6mmeiBoSdH
zL+rc7V8mqntrsZ+6qkNbjOV27zBi47SdDPP8CRnsggO83U/yJsxgruDzs7/f1sM
...

It's actually a long string of text

Generate Certificate Signature Request File CSR

Something used to generate a certificate public key for a certification authority using its root certificate private key signature

Use the following command to generate the CSR:

openssl req -new -key server.key -out server.csr

You need to use the server private key generated by the previous step to create a csr certificate signature request file

Note that you also need to enter the password pass you set when generating the private key

Country Name (2 letter code) []:
State or Province Name (full name) []:
Locality Name (eg, city) []:
Organization Name (eg, company) []:
Organizational Unit Name (eg, section) []:
Common Name (eg, fully qualified host name) []:
Email Address []:
error, no objects specified in config file
problems making Certificate Request

Ask a series of questions. Default blank is not possible. You have to fill in something.

# cat server.csr

-----BEGIN CERTIFICATE REQUEST-----
MIIC6DCCAdACAQAwgYkxCzAJBgNVBAYTAkNOMRIwEAYDVQQIDAlndWFuZ2Rvbmcx
ETAPBgNVBAcMCHNoZW56aGVuMRAwDgYDVQQKDAd0ZW5jZW50MRAwDgYDVQQLDAdz
ZWN0aW9uMRAwDgYDVQQDDAdUZW5jZW50MR0wGwYJKoZIhvcNAQkBFg50ZXN0QGdt
YWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALEcfCsfSxg9
Rc20riGI7j06u3kt5A9+s/RUWYjFMuh9oXpl7njUrZX6rdxA0Ckl+X/9JHjGmYpX
EO23hVCSfyK9fpMd9MiPs5CvFkll3GH7xomif1aRv/ZXkyvTSBpCjRdemysqRy8Y
i+3N8l0qnxIJ5A4LbV4QhjVL+4iv/0Y4zvvjuOY7Rvtm4vU1YiKCS2T6NdJ46Msu
ZRvm8VtKqWtjk1ZM+0iFE8rRFJZ1Jepj+5vtqcqz1s0gKpwZ+jFIhzieGXTuKsp0

Long like this

Remove the passphrase phrase from the private key

Why delete see here: https://blog.longwin.com.tw/2014/08/apache2-nginx-ssl-restart-auto-input-password-2014/

cp server.key server.pass.key
openssl rsa -in server.pass.key -out server.key

This removes the password

Generate self-signed certificate

The final step is to generate a self-signed certificate, which requires the use of the certificate signature request file server.csr and the private key server.key with a validity period of one year:

openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Finally, delete the server.pass.key (dangerous without a key)

The generated file is in a folder and can be read when needed:

.
├── server.crt
└── server.key

Create Service-side App

// app.js

const spdy = require("spdy");
const express = require("express");
const fs = require("fs");
const path = require("path");
const app = express();

app.get("/", function(req, res) {
  res.send("hello world");
});

const options = {
  key: fs.readFileSync(path.resolve(__dirname, "../cert/server.key")),
  cert: fs.readFileSync(path.resolve(__dirname, "../cert/server.crt"))
};

spdy.createServer(options, app).listen(3000, err => {
  if (err) { throw new Error(err) }

  console.log("Listening at: " + 3000);
});

Then node app.js runs and tries to access it using the curl command:

curl https://localhost:3000/ --insecure
curl: (56) LibreSSL SSL_read: SSL_ERROR_SYSCALL, errno 54
RangeError: Invalid typed array length: -4095

😐

Incorrectly, a search on the Internet found that it was a node version problem:

https://github.com/spdy-http2/node-spdy/issues/350

Try switching node version to v10:

node -v
v10.15.3

Start again:

[nodemon] 1.18.11
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `node app.js`
Listening at: 3000.

Access with browser:

protocol: h2 ~ 🚀

Try server push

One of the main features of h2 is the ability of service side push, which can be easily achieved by using spdy module:

Create a new picture in the project directory, we are going to use push to push static resources such as pictures to the client

Modify the APP code as follows:

const spdy = require("spdy");
const express = require("express");
const fs = require("fs");
const path = require("path");
const app = express();

app.get("/app.js", (req, res) => {
  res.end(fs.readFileSync("./app.js"));
});

app.get("/", (req, res) => {
  res.push("/test.png", { method: "GET" }).end(fs.readFileSync("./test.png"));
  //   res.push("/app.js", { method: "GET" }).end(fs.readFileSync('./app.js'));

  res.end(`
<html>
<head>
<script src="/app.js"></script>
</head>
<body><img src="/test.png"></body>
</html>
  `);
});

const options = {
  key: fs.readFileSync(path.resolve(__dirname, "../cert/server.key")),
  cert: fs.readFileSync(path.resolve(__dirname, "../cert/server.crt"))
};

spdy.createServer(options, app).listen(3000, err => {
  if (err) {
    throw new Error(err);
  }

  console.log("Listening on port: " + 3000 + ".");
});

The code above opens the push of the test.png picture file, while the push of the js file is not:

Picture does use push

Modify Code:

app.get("/", (req, res) => {
  res.push("/test.png", { method: "GET" }).end(fs.readFileSync("./test.png"));
  res.push("/app.js", { method: "GET" }).end(fs.readFileSync("./app.js"));

  // ...

The script file also successfully uses push:

done

Reference resources:

Keep an eye on my subscription number, periodically push technical articles about JS, just talk about technology, not gossip.

Keywords: node.js OpenSSL SSL curl Nginx

Added by Zero20two on Wed, 17 Jul 2019 19:48:07 +0300