HTTP/2

While it was introduced in 2015, the adoption of the technology is slow. HTTP/2 builds on the HTTP/1.1 protocol to allow for various features that caused issues for the previous system. This gives us the ability to use a single TCP connection to receive different requests. This wasn't possible with HTTP/1.1 and it caused an issue called head of line blocking. This meant that we could only really handle so many TCP connections and that if we had a long-running TCP connection, it could block all of the requests after it.

HTTP/2 also gave us the ability to push server-side resources. This means that if a server knows that a resource is going to be needed by a browser, such as a CSS file, it could push it to the server before it was needed. Finally, HTTP/2 gave us built-in streaming capabilities. This means we're able to use a connection and send data down as a stream instead of needing to send it all at once.

There are other benefits that HTTP/2 gives us, but these are the main ones. While the http and https modules will probably still be used for some time to come, the http2 module in Node.js should be used for any new applications.

The http2 module in Node.js differs from the http and https modules in a few ways. While it doesn't follow the standards that many of the other IPC/networking modules give us, it does give us some nice ways to send data over HTTP/2. One of these allows us to stream files directly from the filesystem instead of needing to create a pipe for the file and send it to the sender. An example of some of these differences can be seen in the following code:

import http2 from 'http2';
import fs from 'fs';
const server = http2.createSecureServer({
key : fs.readFileSync('server.key.pem'),
cert : fs.readFileSync('server.crt.pem')
});
server.on('error', (err) => console.error(err));
server.on('stream', (stream, headers) => {
stream.respond({
'content-type': 'text/plain',
':status' : 200
});
stream.end('Hello from Http2 server');
});
server.listen(8081, '127.0.0.1');

First, notice that the server needs a private key and a public certificate. These are used to make sure that the connection that is set up is secure, meaning that no one can see what's being sent. For us to be able to do this, we need a tool such as openssl to create these keys and certificates. With Windows 10 and other Unix operating systems, we get this for free. Otherwise, we need to download Cygwin (http://www.cygwin.com/). With openssl, we can run the following command:

> openssl req -x509 -newkey rsa:4096 -keyout server.key.pem -out server.crt.pem -days 365

This command generates the necessary private key and public certificate for the server and clients to communicate securely. We won't go into the details of how this is implemented here, but information on how this can be achieved with SSL/TLS can be found at: https://www.cloudflare.com/learning/ssl/transport-layer-security-tls/.

With our certificate and key generated, we can read them in so that our server can start running. We will also notice that instead of responding to a message event or a request event, we respond to the stream event. HTTP/2 utilizes streams instead of trying to send all of the data at once. While Node.js wrapped the requests and responses in streams for us, this is not how it may be handled at the OS layer. HTTP/2 utilizes streaming right away. This is the reason why the event is called a stream.

Next, instead of calling the writeHead method, we are just responding to the stream. When we want to send information, we utilize the respond method and send the headers this way. We will also notice that some of the headers are prefixed with a colon. This is specific to the http2 module and if problems are found when sending specific headers, putting a colon in front may solve the issue.

Other than what we've talked about here, this should look quite similar to a normal HTTP(s) server that we write in Node.js. There are some other benefits that we get with the http2 module, however, and one of them is responding with a file instead of having to read in that file and send it that way. This can be seen in the following code:

import http2 from 'http2';
import fs from 'fs';
import path from 'path';

const basePath = process.env.npm_package_config_static; //1.
const supportedTypes = new Set(['.ico', '.html', '.css', '.js']);
const server = http2.createSecureServer({
key : fs.readFileSync(process.env.npm_package_config_key),
cert : fs.readFileSync(process.env.npm_package_config_cert),
allowHTTP1 : true //2.
});
server.on('error', (err) => console.error(err));
server.on('stream', (stream, header) => {
const fileLoc = header[':path'];
const extension = path.extname(fileLoc); //3.
if(!supportedTypes.has(extension)) {
stream.respond({
':status' : 400,
'content-type' : 'application/json'
});
stream.end(JSON.stringify({
error : 'unsupported data type!',
extension
}));
return;
}
stream.respondWithFile( //4.
path.join(process.cwd(), basePath, fileLoc),
{
':status' : 200,
'content-type' :
extension === ".html" ?
'text/html' :
extension === ".css" ?
'text/css' :
'text/javascript'
},
{
onError : (err) => { //5.
if( err.code === 'ENOENT') {
stream.respond({ ':status' : 404 });
} else {
stream.respond({ ':status' : 500 });
}
stream.end();
}
}
)
});
server.listen(80, '127.0.0.1');

The program numbers are key points of interest, and they work as follows:

  1. We are reading information from the package.json file, just like we did in the previous chapter. We are also running this through the npm run <script> command. Check out the previous chapter to see how to do this and how we can use configuration data from the package.json file in our programs.
  2. We have set a specific configuration option for our server. If the client that connects to us can't use HTTP/2, then we will automatically convert everything back into the negotiated protocol, for example, HTTP/1.1.
  3. We grab the extension from the URL. This way, we can see whether we support that file type and send the appropriate file; otherwise, we will pass back a 400 error message and state that it was a bad request.
  4. This method allows us to pass a path in. Then, the core system will handle sending the file for us. All we need to do is make sure that we set the content type correctly so that the browser can interpret the data for us.
  5. If there is an error at any point, such as the file not existing, we will respond with the correct status, such as a 404 or a 500 error.

While what we've presented here is just a small fraction of the http2 module, this showcases how the http2 module is different and how we can set one up quite quickly. If need be, refer back to https://Node.js.org/dist/latest-v12.x/docs/api/http2.html to see how the http2 module is different from http and all of the capabilities that come with it. Now, we will take a look at the future state of the web and take a look at HTTP/3 in Node.js.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.35.122