HTTP / 1与HTTP / 2共享的请求语义不同,因此需要在HTTP / 2服务器中检测并处理HTTP /
1客户端。为了同时支持两者,您需要使用HTTP2兼容性API。
当HTTP1客户端连接到具有
allowHTTP1: true设置的HTTP / 2服务器但不处理HTTP / 1请求时,将发生“挂起” 。
这些示例基于Node文档的示例代码。
HTTP / 1和/ 2混合服务器
const http2 = require('http2')const fs = require('fs')var options = { key: fs.readFileSync('server-key.pem'), cert: fs.readFileSync('server-crt.pem'), //ca: fs.readFileSync('ca-crt.pem'), allowHTTP1: true,}var server = http2.createSecureServer(options, (req, res) => { // detects if it is a HTTPS request or HTTP/2 const { socket: { alpnProtocol } } = (req.httpVersion === '2.0') ? req.stream.session : req res.writeHead(200, { 'content-type': 'application/json' }) res.end(JSON.stringify({ alpnProtocol, httpVersion: req.httpVersion }))})server.listen(8443)HTTP / 2客户端
const http2 = require('http2')const fs = require('fs')const client = http2.connect('https://localhost:8443', { ca: fs.readFileSync('ca-crt.pem'), rejectUnauthorized: true,})client.on('socketError', (err) => console.error(err))client.on('error', (err) => console.error(err))const req = client.request({ ':path': '/' })req.on('response', (headers, flags) => { for (const name in headers) { console.log('Header: "%s" "%s"', name, headers[name]) }})req.setEncoding('utf8')let data = ''req.on('data', chunk => data += chunk)req.on('end', () => { console.log('data:', data) client.destroy()})req.end()然后运行:
→ node http2_client.js (node:34542) ExperimentalWarning: The http2 module is an experimental API.Header: ":status" "200"Header: "content-type" "application/json"Header: "date" "Sat, 02 Dec 2017 23:27:21 GMT"data: {"alpnProtocol":"h2","httpVersion":"2.0"}HTTP / 1客户端
const https = require('https')const fs = require('fs')var options = { method: 'GET', hostname: 'localhost', port: '8443', path: '/', protocol: 'https:', ca: fs.readFileSync('ca-crt.pem'), rejectUnauthorized: true, //agent: false}var req = https.request(options, function(res){ var body = '' res.setEncoding('utf8') res.on('data', data => body += data) res.on('end', ()=> console.log('Body:', body))})req.on('response', response => { for (const name in response.headers) { console.log('Header: "%s" "%s"', name, response.headers[name]) }})req.end()然后跑步
→ node http1_client.js Header: "content-type" "application/json"Header: "date" "Sat, 02 Dec 2017 23:27:08 GMT"Header: "connection" "close"Header: "transfer-encoding" "chunked"Body: {"alpnProtocol":false,"httpVersion":"1.1"}HTTP / 2服务器
使用纯HTTP / 2服务器可与一起使用,
http2_client但将“挂起”用于
http1_client。删除时,来自HTTP /
1客户端的TLS连接将关闭
allowHTTP1: true。
const http2 = require('http2')const fs = require('fs')var options = { key: fs.readFileSync('server-key.pem'), cert: fs.readFileSync('server-crt.pem'), ca: fs.readFileSync('ca-crt.pem'), allowHTTP1: true,}var server = http2.createSecureServer(options)server.on('error', error => console.log(error))server.on('connect', conn => console.log('connect', conn))server.on('socketError', error => console.log('socketError', error))server.on('frameError', error => console.log('frameError', error))server.on('remoteSettings', settings => console.log('remote settings', settings))server.on('stream', (stream, headers) => { console.log('stream', headers) stream.respond({ 'content-type': 'application/html', ':status': 200 }) console.log(stream.session) stream.end(JSON.stringify({ alpnProtocol: stream.session.socket.alpnProtocol, httpVersion: "2" }))})server.listen(8443)证书
根据要点中详细描述的扩展中间证书设置,需要将CA的完整证书链提供给客户端。
cat ca/x/certs/x.public.pem > caxy.pemcat ca/y/certs/y.public.pem >> caxy.pem
然后在客户端中使用此
ca选项。
{ ca: fs.readFileSync('caxy.pem'),}这些示例是使用来自circle.com的以下简单CA设置运行的:
为了简化配置,让我们获取以下CA配置文件。
wget https://raw.githubusercontent.com/anders94/https-authorized-clients/master/keys/ca.cnf
接下来,我们将使用此配置创建一个新的证书颁发机构。
openssl req -new -x509 -days 9999 -config ca.cnf -keyout ca-key.pem -out ca-crt.pem现在,我们已经在ca-key.pem和ca-crt.pem中拥有了证书颁发机构,现在让我们为服务器生成一个私钥。
openssl genrsa -out server-key.pem 4096我们的下一步是生成证书签名请求。再次简化配置,让我们使用server.cnf作为配置快捷方式。
wget https://raw.githubusercontent.com/anders94/https-authorized-clients/master/keys/server.cnf
现在,我们将生成证书签名请求。
openssl req -new -config server.cnf -key server-key.pem -out server-csr.pem现在让我们签署请求。
openssl x509 -req -extfile server.cnf -days 999 -passin "pass:password" -in server-csr.pem -CA ca-crt.pem -CAkey ca-key.pem -CAcreateserial -out server-crt.pem



