支持 CONNECT 方法
CONNECT
方法用于允许 HTTP/2 服务器用作 TCP/IP 连接的代理。
简单的 TCP 服务器:
const net = require('node:net');
const server = net.createServer((socket) => {
let name = '';
socket.setEncoding('utf8');
socket.on('data', (chunk) => name += chunk);
socket.on('end', () => socket.end(`hello ${name}`));
});
server.listen(8000);
HTTP/2 CONNECT 代理:
const http2 = require('node:http2');
const { NGHTTP2_REFUSED_STREAM } = http2.constants;
const net = require('node:net');
const proxy = http2.createServer();
proxy.on('stream', (stream, headers) => {
if (headers[':method'] !== 'CONNECT') {
// 只接受 CONNECT 请求
stream.close(NGHTTP2_REFUSED_STREAM);
return;
}
const auth = new URL(`tcp://${headers[':authority']}`);
// 验证主机名和端口是此代理应该连接的对象
// 是一个很好的主意。
const socket = net.connect(auth.port, auth.hostname, () => {
stream.respond();
socket.pipe(stream);
stream.pipe(socket);
});
socket.on('error', (error) => {
stream.close(http2.constants.NGHTTP2_CONNECT_ERROR);
});
});
proxy.listen(8001);
HTTP/2 CONNECT 客户端:
const http2 = require('node:http2');
const client = http2.connect('http://localhost:8001');
// 不得为 CONNECT 请求指定 ':path' 和 ':scheme' 标头,
// 否则将引发错误。
const req = client.request({
':method': 'CONNECT',
':authority': `localhost:${port}`,
});
req.on('response', (headers) => {
console.log(headers[http2.constants.HTTP2_HEADER_STATUS]);
});
let data = '';
req.setEncoding('utf8');
req.on('data', (chunk) => data += chunk);
req.on('end', () => {
console.log(`The server says: ${data}`);
client.close();
});
req.end('Jane');
The CONNECT
method is used to allow an HTTP/2 server to be used as a proxy
for TCP/IP connections.
A simple TCP Server:
const net = require('node:net');
const server = net.createServer((socket) => {
let name = '';
socket.setEncoding('utf8');
socket.on('data', (chunk) => name += chunk);
socket.on('end', () => socket.end(`hello ${name}`));
});
server.listen(8000);
An HTTP/2 CONNECT proxy:
const http2 = require('node:http2');
const { NGHTTP2_REFUSED_STREAM } = http2.constants;
const net = require('node:net');
const proxy = http2.createServer();
proxy.on('stream', (stream, headers) => {
if (headers[':method'] !== 'CONNECT') {
// Only accept CONNECT requests
stream.close(NGHTTP2_REFUSED_STREAM);
return;
}
const auth = new URL(`tcp://${headers[':authority']}`);
// It's a very good idea to verify that hostname and port are
// things this proxy should be connecting to.
const socket = net.connect(auth.port, auth.hostname, () => {
stream.respond();
socket.pipe(stream);
stream.pipe(socket);
});
socket.on('error', (error) => {
stream.close(http2.constants.NGHTTP2_CONNECT_ERROR);
});
});
proxy.listen(8001);
An HTTP/2 CONNECT client:
const http2 = require('node:http2');
const client = http2.connect('http://localhost:8001');
// Must not specify the ':path' and ':scheme' headers
// for CONNECT requests or an error will be thrown.
const req = client.request({
':method': 'CONNECT',
':authority': `localhost:${port}`,
});
req.on('response', (headers) => {
console.log(headers[http2.constants.HTTP2_HEADER_STATUS]);
});
let data = '';
req.setEncoding('utf8');
req.on('data', (chunk) => data += chunk);
req.on('end', () => {
console.log(`The server says: ${data}`);
client.close();
});
req.end('Jane');