[译] Node.js, Express.js 搭建 HTTP/2 服务器

原文:Easy HTTP/2 Server with Node.js and Express.js
作者:Azat Mardan
代码:http2-express


什么是 HTTP/2

现代互联网的 TCP/IP 协议发布于1975年,这项技术在41年前是多么令人惊讶。自它发布开始大部分形式,我们使用 HTTP 和 后续接任者 HTTP/1.1 来实现客户端和服务端的通讯。它能很不错的传输 Web,但今时今日的开发者建立网站的方式已经发生了巨大的改变。存在各式各样的外部资源链接例如图片、CSS 文件、JavaScript 资源。资源的种类数量只会持续增长。

HTTP/2 是针对表现一直不错的旧协议 HTTP 自从1991年发布以来这15年的第一次大的升级改动!它为优化现代浏览器而生。性能更加优越而且不用使用复杂的行为例如域名分片(通过多个域名发送资源)或者资源文件合并`(提供一个整合的大资源而不是多个小资源)

HTTP/2 是当前 web 的新标准,其雏形是 Google 的 SPDY 协议。当前已经被大多数主流浏览器支持,且很多网站已经通过该协议实现。例如访问 Yahoo 的 Flickr 在使用的是 HTTP/2 协议(截图时间为2016年7月).

HTTP/2 的优势和注意事项

HTTP/2HTTP/1.1 的使用没什么区别,仍然可以在 body 中使用类 xml 的语法,使用 header 协议头字段, 状态码, cookies, methods, URLs, 等等。开发者熟悉使用的东西都还可以继续在 HTTP/2 使用。

HTTP/2的优势如下:

  1. 多路复用传输(Multiplexing):允许浏览器在单个TCP连接中包含多个请求,从而使浏览器能够并行地请求所有的资源;
  2. 服务器推送(Server push):服务器可以在浏览器知道需要该资源前,推送给浏览器(如:CSS、JS、Image),从而通过减少请求数量来加速页面加载时间;
  3. 流传输优先级(Stream priority):允许浏览器去控制资源的加载优先级,例如,浏览器先请求 HTML 渲染再去加载其他的 CSSJS 文件;
  4. 头部压缩(Header compression): HTTP/1.1 请求的头部总是重复一样的内容,而 HTTP/2 则强制对所有请求的头部进行了去重压缩;
  5. 实际的强制加密(De facto mandatory encryption):虽然加密不是硬性要求的,但是大多数浏览器只支持 TLS(HTTPS) 上的 HTTP/2

虽然目前对于 HTTP/2 还不能完全满足一些苛求,但是直到更好的技术出现以前,当前是一项明显的技术进步。让我们来看看,作为 Web 开发者需要了解的必要知识。大部分适用于 HTTP/1.1 的优化技巧在 HTTP/2 中变成多余的,其中一些甚至反而会影响 HTTP/2 上的网站性能,例如:

  1. 资源文件合并;
  2. 你也应该停止使用精灵图(image sprites)、CSS和JS打包,因为只要其中一小部分有改动就会影响客户端的缓存的作用;在 HTTP/2 协议上更好的方式是使用多个的小文件,而不是一个大文件。
  3. 作者希望前端构建工具,如 GruntGulpWebpack 将会因此特性被放弃使用,他们使 Web 开发更高的复杂度,极高的学习曲线,以及管理项目的依赖关系。
  4. 另一个适用于 HTTP/1.1 不适用于 HTTP/2 的是,域名分片(为了绕过TCP并行请求数量限制)。虽然它不一定在所有情况下有害,但对于 HTTP/2 的多路复用传输,这样做也已经没好处了。之所以建议不在 HTTP/2 使用域名分片,还因为每个域名会带来额外的查询负载。如果真的有需要,那么更好的方式是解析多个域名到同一个IP,而且保证你使用的是通配符证书或整合了多域名的证书,从而减少域名查询的时间。

若想了解更多关于 HTTP/2 的介绍,可以看看官网

Node.js 搭建 HTTP/2

现在,让我们看看怎么通过 Node.js 搭建 HTTP/2 服务器。

部署证书

创建一个新文件夹以及自己签发的 SSL 证书。

$ mkdir http2-express 
$ cd http2-express
$ openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
...
$ openssl rsa -passin pass:x -in server.pass.key -out server.key
writing RSA key
$ rm server.pass.key
$ openssl req -new -key server.key -out server.csr
...
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:California
...
A challenge password []:
...
$ openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt

当你访问服务器的时候,因为浏览器默认不信任自己签发的证书,请确保选择 “高级” 和 “继续访问 localhost (不安全)” 或者将 localhost 设置成不安全访问的例外。

初始化、依赖、入口

通过 npm ,初始化项目 package.json ,安装依赖 spdyexpress

npm init
npm i express spdy --save

创建应用的入口文件 index.js ,主要是引用以及实例化

const port = 3000
const spdy = require('spdy')
const express = require('express')
const path = require('path')
const fs = require('fs')

const app = express()

定义 Express.js 的 route

实现 Express.jsroute

app.get('*', (req, res) => {
res
.status(200)
.json({message: 'ok'})
})

设置证书以及启动 Server

通过 fs.readFileSync() 读取证书

const options = {
key: fs.readFileSync(__dirname + '/server.key'),
cert: fs.readFileSync(__dirname + '/server.crt')
}

然后,设置证书选项到 Express 对象:

spdy
.createServer(options, app)
.listen(port, (error) => {
if (error) {
console.error(error)
return process.exit(1)
} else {
console.log('Listening on port: ' + port + '.')
}
})

最后,node . 启动服务器

检查结果

通过浏览器的开发者工具查看协议,就如刚刚我们查看 Yahoo 的 Flickr 协议一样。

可以看到,使用 Node.js 和 Express.js 配合库 node-spdy 实现 HTTP/2 简单易懂。大多数情况下,对你的业务代码是基本不需要修改的,想必,你的网站也已经使用了 HTTPS/SSL (除非你的服务器只提供静态资源,否则你应该使用安全的 HTTPS/SSL ),即使是不使用 HTTP/2 你也可以替换 HTTP/1.1 而使用 SPDY

当然,在 Node.js 的大环境中,有很多的库,不只是 node-spdy 提供 HTTP/2 实现,例如:node-http2

结语

HTTP/2 提供了更多更优的好处,而且不用使用复杂的优化技巧。开始享受 HTTP/2 给你带来的这些好处。展望光明的未来!

PS: 本文源代码地址在 http2-express