原文: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/2
和 HTTP/1.1
的使用没什么区别,仍然可以在 body
中使用类 xml
的语法,使用 header
协议头字段, 状态码, cookies, methods, URLs, 等等。开发者熟悉使用的东西都还可以继续在 HTTP/2
使用。
HTTP/2
的优势如下:
- 多路复用传输(Multiplexing):允许浏览器在单个TCP连接中包含多个请求,从而使浏览器能够并行地请求所有的资源;
- 服务器推送(Server push):服务器可以在浏览器知道需要该资源前,推送给浏览器(如:CSS、JS、Image),从而通过减少请求数量来加速页面加载时间;
- 流传输优先级(Stream priority):允许浏览器去控制资源的加载优先级,例如,浏览器先请求
HTML
渲染再去加载其他的CSS
和JS
文件; - 头部压缩(Header compression):
HTTP/1.1
请求的头部总是重复一样的内容,而HTTP/2
则强制对所有请求的头部进行了去重压缩; - 实际的强制加密(De facto mandatory encryption):虽然加密不是硬性要求的,但是大多数浏览器只支持
TLS(HTTPS)
上的HTTP/2
。
虽然目前对于 HTTP/2
还不能完全满足一些苛求,但是直到更好的技术出现以前,当前是一项明显的技术进步。让我们来看看,作为 Web
开发者需要了解的必要知识。大部分适用于 HTTP/1.1
的优化技巧在 HTTP/2
中变成多余的,其中一些甚至反而会影响 HTTP/2
上的网站性能,例如:
- 资源文件合并;
- 你也应该停止使用精灵图(image sprites)、CSS和JS打包,因为只要其中一小部分有改动就会影响客户端的缓存的作用;在
HTTP/2
协议上更好的方式是使用多个的小文件,而不是一个大文件。 - 作者希望前端构建工具,如
Grunt
、Gulp
、Webpack
将会因此特性被放弃使用,他们使Web
开发更高的复杂度,极高的学习曲线,以及管理项目的依赖关系。 - 另一个适用于
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
,安装依赖 spdy
和 express
:
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.js
的 route
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
我的博客