Practical Node.js (2018版) 13章, Node HTTP/2 Servers

新增的章节。

If you are not using HTTP/2, then you are losing out on big improvements. 

HTTP/2相比http/1有很大的区别。例如:

  • multiplexing 多路复用
  • server push of assets

如果您没有用HTTP/2优化代码,那么您的应用程序可能比使用HTTP/2要慢。

大量http/1的网页优化实际已经不需要了,甚至它们可能会伤到HTTP/2。

 

本章介绍一些主要功能,你需要阅读它并跟着它进行更多的在线阅读。

 

相关连接:

https://nodejs.org/api/http2.html

http://expressjs.com/en/4x/api.html 

 


 

Brief Overview of HTTP/2

 

  • 多路传输Multiplexing: Allows browsers to include multiple requests in a single TCP connection that enables browsers to request all the assets in parallel.
  • 服务器推送Server push: Servers can push web assets (CSS, JS, images) before a browser knows it needs them, which speeds up page load times by reducing the number of requests.
  • 流优先Stream priority: Allows browsers to specify priority of assets. For example, a browser can request HTML first to render it before any styles or JavaScript.
  • 头压缩Header compression: All HTTP/1.1 requests have to have headers which are typically duplicate the same info, while H2 forces all HTTP headers to be sent in a compressed format.
  • De facto mandatory encryption: Although the encryption is not required, most major browsers implement H2 only over TLS (HTTPS).

作为web开发者需要知道的是:

原先的大多数优化计策已经不需要了。尤其是文件串联the file concatenation。

Stop doing that (image sprites, bundled CSS and JS), because H2 can make parallel requests and because each small change in your big file will invalidate cache.

It’s better to have many small files with H2.

I hope the need for build tools like Grunt, Gulp, and Webpack will drop because of that. 

 

Don’t do domain sharding in HTTP2.

请学习所有的HTTP/2细节,可以从这篇文章开始:https://http2.github.io/faq/ 

 

SSL Key and Certificate

当浏览一个https网页,地址栏上有一个?符号,点击可以查看连接证书,代表它是一个可信任的源。

 

为了开发,可以创建一个自我标记self-signed的证书和key,代替花钱的官方认证。

这个证书不是真的,因此使用它,在chrome上有⚠️提示信息。 

不过开发阶段,没问题!

 

openssl

是目前最流行的 SSL 密码库工具,其提供了一个通用、健壮、功能完备的工具套件,用以支持SSL/TLS 协议的实现。

官网:https://www.openssl.org/source/

1.02版本的说明:https://www.openssl.org/docs/man1.0.2/man1/openssl.html

⚠️1.02版本在2019年过后官方不再提供支持。 建议使用1.1.1版本。

 

使用HomeBrew下载安装openssl:

//mac自带版本太旧

brew install openssl
// 把路径字符串存入环境变量PATH,然后export导出环境变量,然后>>把这行代码存入到脚本文件最后。

echo 'export PATH="/usr/local/opt/openssl/bin:$PATH"' >> ~/.bash_profile source ~/.bash_profile

 

生产一个RSA私人keyserver.pass.key, 不要和别人分享你的私人key:

$ openssl genrsa -des3 -passout pass:x -out server.pass.key 2048

 

 然后使用这个私人?,产生 server.key, 这是你的RSA key:

$ openssl rsa -passin pass:x -in server.pass.key -out server.key

 

删除server.pass.key

还需要一个证书certificate, 使用server.key生成一个csr 文件 :

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

 

这里会要求输入一堆问题,关于地址,公司等等,既然是开发阶段,可以忽略。

最后,sign(server.key) the certificate(证书server.csr) to generate the server.crt:

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

 

提示

Signature ok
subject=/C=US/ST=newland/O=Internet Widgits Pty Ltd
Getting Private key

 

保留2个文件server.crt, server.key

可以扔掉csr文件。


 

HTTP/2 Node Server

http2的接口和http/https接口大部分兼容。

新建文件夹http2, 然后npm init -y, 把?2个文件server.crt, server.key移动过来。

新建文件server.js,  然后:

1. import和定义变量。

2.实例化server。 使用http2.createSecureServer(), 它包括2个参数:

  •  SSL 编码。 这里使用2个文件的内容: key和signed certificate。
  •  定义请求处理函数handler。这和http模块定义请求处理函数类似。

第一个参数内,使用fs模块读取文件。

第二个参数内,res.end()方法实际调用http2模块中的类http2ServerResponse中的实例方法response.end()

  • 这个方法发送信号给server,所有的响应头和体都已经发送,server应该认为信息完成。
const http2 = require('http2')
const fs = require('fs')

const server = http2.createSecureServer({
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt')
}, (req, res) => {
  res.end('hello')
})

server.on('error', (err) => console.error(err))
server.listen(3000)

 

流的写法stream:

我们也可以使用stream重写上面的例子。

分配一个事件监听(on()方法)来捕捉stream events。

我们能够使用respond(), end()方法在stream object上设置headers, status,并返回<h1>

const http2 = require('http2')
const fs = require('fs')

const server = http2.createSecureServer({
  key: fs.readFileSync('server.key')
  cert: fs.readFileSync('server.crt')
})

server.on('error', (err) => console.error(err))
server.on('socketError', (err) => console.error(err))

server.on('stream', (stream, headers) => {
  stream.respond({
    'content-type': 'text/html',
    ':status': 200
  })
  stream.end('<h1>Hello World</h1>')
})

server.listen(3000)

此时server是一个安全的HTTP/2 server实例 。它也是一个ServerHttp2Stream的实例。

 


 

 

知识扩展:

Class: Http2Stream

在服务器,Http2Stream实例被创建的背景:

  • 响应一个进入的Http请求(并通过stream事件转化到user code),或者
  • 响应一个http2stream.pushStream()方法的调用时创建Http2Stream

在客户端, Http2Stream实例被创建和返回,当:

  • http2session.request()方法被调用 ,或者
  • 响应一个进入的push事件。

这个Http2Stream类是是ServerHttp2Stream和ClientHttp2Stream类的基础。

所有的Http2Stream实例是Duplex streams。

  • Duplex stream的Writable一边是用于发送数据给连接的一端。
  • 而,Readable一边是用于接收由连接的另一端发过来的数据。

 

Http2Stream Lifecycle

创建和销毁destruction。

创建:

在服务器端,实例ServerHttp2Stream被创建的时刻:

  • 当一个新Http/2 HEADERS frame和一个之前未使用过的stream?被收到
  • http2stream.pushStream方法被调用时。

在客户端,实例ClientHttp2Stream被创建的时刻:当http2session.request()方法被调用时。

 


 

 

 

最后node server.js, 然后https://localhost:3000

出现❌的画面:

点击Proceed to localhost (unsafe), 进入本地页面。显示标题Hello World

点击地址栏上的红字‘⚠️not Secure’,显示相关证书信息。

 

使用chrome的inspector可以看到这个网页使用了h2协议。

 

 

 

 


 

Node HTTP/2 Server Push

 

一个比Multiplexing还要棒的功能,官方博客形容是一个量级的飞跃!

server push 绑定所有的资源进入一个Http/2 call。

server会发出一个PUSH_PROMISE

浏览器根据自身的主HTML文件需要,来决定是否使用它。

如果需要,浏览器会匹配收到的push promises,让它们看起来像一个标准的HTTp/2 GET call。

如果匹配到了,资源就会被浏览器使用,无需在发出新的请求了。

Server push不保证一定降低加载时间:

What’s the benefit of Server Push?

当浏览器请求一个网页,服务器会发出响应,然后服务器会等待浏览器解析HTML后发出请求所有嵌套资源的request, 然后服务器在收到请求后会发出这些资源: JS, Images, css。

Server Push允许服务器避开这一圈旅行,减少了等待时间。它会把所有client可能需要的资源一次性打包到一个response内,client会把这些资源存在它的cache内。

注意,Pushing response不是魔法,不正确的使用会伤害执行performance。

正确使用Server Push是一个持续的实验和搜索。

 

Announcing Support for HTTP/2 Server Push

Http2 server Push是一个现代的更高效的功能,等同于Http/1.1的inlining assets。

Inlining 是你把额外的Js和css资源放入网页的<script>和<style>元素内。

这个目标是最小化浏览器和服务器的HTTP请求的数量。

Server Push也可以做到,但是它是让资源独立的缓存到浏览器。 

 

需要注意的是,Server Push有些机会主意,在有些案例,发出的资源其实客户端根本不需要或者已经存在于客户端缓存内了。

谨慎的使用,Server Push会改善运行.

它会发出PUSH_PROMISE--一个意图发送资源的声明,跟着实际的assets。

 

使用server push
如果你想要push assets到一个request, 需要增加一个link header给response。 
Link: </asset/to/push.js>; rel=preload; as=script

这个links可以手动添加,不管它们会被自动的创建,通过一些发布工具或插件。

 

Server Push是否适合我?

使用好处很多,但不会加速所有的网页website。比如推送不需要的资源会浪费带宽。

我们建议用和不用都试试,看看哪个更快。

还要注意,push的资源来自你的domain。如果你使用了第三方资源,这个功能不会管用。

  • Uncacheable content - Content that is not cached on the edge benefits from Server Push, since it will be requested from the origin earlier in the connection.

  • All assets on a requested page - By pushing all the CSS, JS, and image assets on a given page, it’s possible to transfer the entire page in a single round trip. This is only useful when no third party assets are blocking the page rendering. If the majority of the assets are cached on the client’s browser, this behavior can be wasteful.

  • The most likely next page - If there is a link on the loaded page that is most likely clicked next (for example the most recent post in a blog) you could push both the HTML and all of that pages assets. When the user clicks the link, it will render almost instantly.

 

使用push stream

上面的案例修改:

const http2 = require('http2')
const fs = require('fs')

const server = http2.createSecureServer({
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.crt')
})

server.on('error', (err) => console.error(err))
server.on('socketError', (err) => console.error(err))

server.on('stream', (stream, headers) => {
  stream.respond({
    'content-type': 'text/html',
    ':status': 200
  })
  stream.pushStream({ ':path': '/myfakefile.js' }, (error, pushStream) => {
if (error) throw error; pushStream.respond({
'content-type': 'text/javascript', ':status': 200 }) pushStream.end(`alert('you win')`) }) stream.end('<script src="/myfakefile.js"></script><h1>Hello World</h1>') }) server.listen(3000)

 

首先理解stream.pushStream(headers, callback(err, pushStream)) , 它的作用是初始化一个push stream。回调函数使用新创建的HttpStream实例作为第二个参数,用于push stream,一个Error实例作为第一个参数。

再看pushStream.respond([headers], options), 一个实例方法 。设置响应的头部。

 

解释:

服务器发送HTML,同时也会发送一个myfakefile.js文件及一条提示代码。这就是Server push。

到了浏览器,脚本文件不会被加载或者执行,直到浏览器看到HTML代码内有一个<script>元素,并再这个元素找到myfakefile.js文件,浏览器会再到自身缓存内查找是否有这个文件,找到后,加载这个文件。如果没有找到,则向服务器发出请求。

 

Summary

building an HTTP/2 server with Node.js and Express.js is straightforward.

 

In the end, HTTP/2 offers more benefits and removes the complexity of some web-optimization tricks.

 

 


 

转载于:https://www.cnblogs.com/chentianwei/p/10346329.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值