Flutter 项目里用到了 http2 包 (https://pub.dev/packages/http2) 。但官方似乎没有支持 http proxy ,转念一想,似乎也对,proxy 这层不属于 http2 协议该负责实现的事。

研究了一下 http/1.1 tunnel proxy 的协议(RFC 2817)发现其实挺简单的。

这里直接放出示例了,仅供参考哦(需要登录的 proxy 就留给你自己实现了)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:http2/http2.dart';

void main() async {
var uri = Uri.parse('https://cn.bing.com/search?q=http2');
var transport = await connectTunnel('127.0.0.1', 8888, uri.host);
var headers = [
Header.ascii(':method', 'GET'),
Header.ascii(':path', uri.hasQuery ? uri.path + '?' + uri.query : uri.path),
Header.ascii(':scheme', uri.scheme),
Header.ascii(':authority', uri.host),
];
var stream = transport.makeRequest(headers, endStream: true);
var bodyStream = StreamController<List<int>>();
utf8.decoder.bind(bodyStream.stream).listen((body) {
print(body);
});
await for (var message in stream.incomingMessages) {
if (message is HeadersStreamMessage) {
for (var header in message.headers) {
var name = utf8.decode(header.name);
var value = utf8.decode(header.value);
print('Header: $name: $value');
}
} else if (message is DataStreamMessage) {
bodyStream.add(message.bytes);
if (message.endStream) {
bodyStream.close();
}
}
}
if (!bodyStream.isClosed) {
await bodyStream.close();
}
await transport.finish();
}

Future<ClientTransportConnection> connectTunnel(String proxyHost, int proxyPort, String targetHost,
[int targetPort = 443]) async {
var proxy = await Socket.connect(proxyHost, proxyPort, timeout: const Duration(seconds: 1));
const CRLF = "\r\n";
proxy.write("CONNECT $targetHost:$targetPort HTTP/1.1"); // request line
proxy.write(CRLF);
proxy.write("Host: $targetHost:$targetPort"); // header
proxy.write(CRLF);
proxy.write(CRLF);
var completer = Completer<bool>.sync();
var sub = proxy.listen((event) {
var response = ascii.decode(event);
var lines = response.split(CRLF);
// status line
var statusLine = lines.first;
if (statusLine.startsWith("HTTP/1.1 200")) {
completer.complete();
} else {
completer.completeError(statusLine);
}
}, onError: completer.completeError);
await completer.future; // established
await sub.pause();

var socket = await SecureSocket.secure(proxy, host: targetHost, supportedProtocols: const ["h2"]);
return ClientTransportConnection.viaSocket(socket);
}

关键 API:

  • Socket.connect
  • SecureSocket.secure
  • ClientTransportConnection.viaSocket

最后,关于 Flutter 如何使用系统代理,请看这篇:https://yrom.net/blog/2020/04/09/load-http-proxy-from-platform-for-flutter-app/