Description
Summary
flutter --version
Flutter 3.29.2 • channel stable • https://github.com/flutter/flutter.git
Framework • revision c236373904 (2 months ago) • 2025-03-13 16:17:06 -0400
Engine • revision 18b71d647a
Tools • Dart 3.7.2 • DevTools 2.42.3
web_socket_channel: ^3.0.3
WebSocketException: Connection to 'http://example.com:80?token=xxx#' was not upgraded to websocket, HTTP status code: 426
When using WebSocket.connect()
with a proxy and a ws://
(non-secure WebSocket) URL, Dart fails to perform a valid WebSocket handshake — the server responds with HTTP 426. The same code works fine with wss://
URLs through the proxy.
The proxy is a standard HTTP proxy (like Clash or Xray).
I verified that curl -x 127.0.0.1:10809 with proper headers works correctly with ws:// over the same proxy.
I have confirmed that the proxy configuration (such as Clash/Xray on localhost 127.0.0.1:10809) works correctly and can successfully proxy ws:// requests. On all platforms — including Android native, iOS, and Windows — the WebSocket handshake completes successfully when using tools like curl, browsers, or Java clients. Only Dart’s WebSocket.connect() fails with a 426 error when attempting to connect via ws:// through a proxy.
Code to reproduce
void connect() async {
try {
wsStatusListener.onConnecting?.call();
final httpClient = HttpClient();
httpClient.findProxy = (uri) {
final proxy = "PROXY 127.0.0.1:10809;";
return proxy;
};
final uri = Uri.parse(url);
final socket = await WebSocket.connect(
uri.toString(),
customClient: httpClient,
);
_channel = IOWebSocketChannel(socket);
_channel!.stream.listen(
(message) {
_handleMessage(message);
},
onError: (error) {
_handleError(error);
},
onDone: () {
_handleDone();
},
);
_reconnectTimer?.cancel();
_reconnectTimer = null;
_isConnected = true;
_startHeartbeat();
_sendFlushMessageQueue();
wsStatusListener.onConnected?.call();
} catch (ex) {
_isConnected = false;
_handleError(ex);
}
}