我希望使用Node.js的 http2 库通过代理向服务器发送HTTP/2请求。为了测试,我使用Charles v4.2.7作为代理,但是Charles无法代理该请求。Charle显示
我想尝试使用Node.js完成相同的操作(首先发送HTTP/1 CONNECT请求,然后在同一TCP连接上发送我的HTTP/2请求),但我不知道该如何做。创建HTTP/2客户端的过程(即
有人可以帮助我使用Node.js通过代理发送HTTP/2请求吗?
更新(2020-07-13):我已经在首先使用HTTP/1创建连接,发送CONNECT请求,然后尝试在同一套接字上使用HTTP/2发送GET请求方面取得了更多进展。我可以在Charles中看到CONNECT请求,但没有看到其他GET请求,这表明在尝试使用同一套接字进行HTTP/2请求时仍然存在错误。以下是我的更新代码:
Malformed request URL "*"
错误,因为它接收到的请求是 PRI * HTTP/2.0
(HTTP/2连接前言)。 我可以通过cURL成功地通过我的Charles代理发送HTTP/2请求(例如:curl --http2 -x localhost:8888 https://cypher.codes
),因此我认为这不是与Charles有关的问题,而是与我的Node.js实现有关的问题。
下面是我的Node.js HTTP/2客户端实现,它尝试通过侦听在http://localhost:8888的Charles代理向https://cypher.codes发送GET请求:const http2 = require('http2');
const client = http2.connect('http://localhost:8888');
client.on('error', (err) => console.error(err));
const req = client.request({
':scheme': 'https',
':method': 'GET',
':authority': 'cypher.codes',
':path': '/',
});
req.on('response', (headers, flags) => {
for (const name in headers) {
console.log(`${name}: ${headers[name]}`);
}
});
req.setEncoding('utf8');
let data = '';
req.on('data', (chunk) => { data += chunk; });
req.on('end', () => {
console.log(`\n${data}`);
client.close();
});
req.end();
在运行node proxy.js
时,我得到了以下Node.js错误信息(proxy.js
是包含上述代码的文件):
events.js:200
throw er; // Unhandled 'error' event
^
Error [ERR_HTTP2_ERROR]: Protocol error
at Http2Session.onSessionInternalError (internal/http2/core.js:746:26)
Emitted 'error' event on ClientHttp2Stream instance at:
at emitErrorNT (internal/streams/destroy.js:92:8)
at emitErrorAndCloseNT (internal/streams/destroy.js:60:3)
at processTicksAndRejections (internal/process/task_queues.js:81:21) {
code: 'ERR_HTTP2_ERROR',
errno: -505
}
我使用详细输出重新运行了上述cURL请求,看起来cURL首先使用HTTP/1向代理发送CONNECT请求,然后使用HTTP/2发送GET请求。
$ curl -v --http2 -x localhost:8888 https://cypher.codes
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8888 (#0)
* allocate connect buffer!
* Establish HTTP proxy tunnel to cypher.codes:443
> CONNECT cypher.codes:443 HTTP/1.1
> Host: cypher.codes:443
> User-Agent: curl/7.64.1
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 200 Connection established
<
* Proxy replied 200 to CONNECT request
* CONNECT phase completed!
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/cert.pem
CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* CONNECT phase completed!
* CONNECT phase completed!
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=cypher.codes
* start date: Jun 21 04:38:35 2020 GMT
* expire date: Sep 19 04:38:35 2020 GMT
* subjectAltName: host "cypher.codes" matched cert's "cypher.codes"
* issuer: CN=Charles Proxy CA (8 Oct 2018, mcypher-mbp.local); OU=https://charlesproxy.com/ssl; O=XK72 Ltd; L=Auckland; ST=Auckland; C=NZ
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7ff50d00d600)
> GET / HTTP/2
> Host: cypher.codes
> User-Agent: curl/7.64.1
> Accept: */*
>
...
我想尝试使用Node.js完成相同的操作(首先发送HTTP/1 CONNECT请求,然后在同一TCP连接上发送我的HTTP/2请求),但我不知道该如何做。创建HTTP/2客户端的过程(即
http2.connect('http://localhost:8888');
)会发送HTTP/2连接序言。我考虑先使用HTTP/1创建连接(例如使用http
库),然后将其升级为HTTP/2,但我找不到任何关于如何执行此操作的示例。有人可以帮助我使用Node.js通过代理发送HTTP/2请求吗?
更新(2020-07-13):我已经在首先使用HTTP/1创建连接,发送CONNECT请求,然后尝试在同一套接字上使用HTTP/2发送GET请求方面取得了更多进展。我可以在Charles中看到CONNECT请求,但没有看到其他GET请求,这表明在尝试使用同一套接字进行HTTP/2请求时仍然存在错误。以下是我的更新代码:
const http = require('http');
const http2 = require('http2');
const options = {
hostname: 'localhost',
port: 8888,
method: 'CONNECT',
path: 'cypher.codes:80',
headers: {
Host: 'cypher.codes:80',
'Proxy-Connection': 'Keep-Alive',
'Connection': 'Keep-Alive',
},
};
const connReq = http.request(options);
connReq.end();
connReq.on('connect', (_, socket) => {
const client = http2.connect('https://cypher.codes', {
createConnection: () => { return socket },
});
client.on('connect', () => console.log('http2 client connect success'));
client.on('error', (err) => console.error(`http2 client connect error: ${err}`));
const req = client.request({
':path': '/',
});
req.setEncoding('utf8');
req.on('response', (headers, flags) => {
let data = '';
req.on('data', (chunk) => { data += chunk; });
req.on('end', () => {
console.log(data);
client.close();
});
});
req.end();
});