“Cannot connect to wss with Flutter” 翻译为中文是 “无法在Flutter中连接到wss”。

huangapple go评论84阅读模式
英文:

Cannot connect to wss with Flutter

问题

我写了一个在Node.js中的wss服务器,现在我正在尝试使用Flutter连接到这个服务器。

以下是Node.js中的代码:

//依赖项
const WebSocket = require('ws');
const fs = require('fs');
const https = require('https');
//依赖项

//服务器声明
const server = https.createServer({
	key: fs.readFileSync('pathTo/key.pem'),
	cert: fs.readFileSync('pathTo/cert.pem')
});
server.listen(xxxx);
const wss = new WebSocket.Server({ server });
//服务器声明

wss.on('connection', function connection(ws)
{
  ws.on('message', function incoming(message)
  {
      console.log('Received: ' + message);
      ws.send('echo: ' + message);
   });
   ws.send('Connected!');
});

以下是Flutter中的代码:

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:web_socket_channel/io.dart';
import 'package:connectivity/connectivity.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

class MyApp extends StatelessWidget
{
  @override
  Widget build(BuildContext context)
  {
    final title = 'LumenApp Prototype';
    IOWebSocketChannel channel;
    try
    {
      channel = new IOWebSocketChannel.connect('wss://xxxxxxxx.xxx.xxx:xxxx/');
      MyHomePageState.noResponse = false;
    }
    catch(e)
    {
      MyHomePageState.noResponse = true;
    }
    return MaterialApp(
      title: title,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        primaryTextTheme: TextTheme(
          title: TextStyle(
            color: Colors.yellow[600],
          ),
        ),
      ),
      home: MyHomePage(
        title: title,
        channel: channel,
      ),
    );
  }
}

在Flutter中的错误是:WebSocketChannelException: WebSocketChannelException: HandshakeException: Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: self signed certificate(handshake.cc:354))

这个错误发生在这个函数内部:

void initPlatformState()
{
  widget.channel.stream.listen((message)
  {
    setState(() { noResponse = false; });
    //处理消息...
  },
  onError: (error)
  {
    print(error);
    if(mounted)
    {
      setState((){ noResponse = true;});
    }
  },
  onDone: ()
  {
    if(mounted)
    {
      setState((){ noResponse = true; });
    }
  });
}

我在服务器端使用了自签名证书,使用了openssl制作。有什么办法解决这个问题吗?

英文:

I wrote a wss server in Nodejs and now I'm trying to connect to such server using Flutter.

Here's the code in NodeJS:<br>

//Dependencies
const WebSocket = require(&#39;ws&#39;);
const fs = require(&#39;fs&#39;);
const https = require(&#39;https&#39;);
//Dependencies

//Server declarations
const server = https.createServer({
	key: fs.readFileSync(&#39;pathTo/key.pem&#39;),
	cert: fs.readFileSync(&#39;pathTo/cert.pem&#39;)
});
server.listen(xxxx);
const wss = new WebSocket.Server({ server });
//Server declarations

wss.on(&#39;connection&#39;, function connection(ws)
{
  ws.on(&#39;message&#39;, function incoming(message)
  {
      console.log(&#39;Received: &#39; + message);
      ws.send(&#39;echo: &#39; + message);
   });
   ws.send(&#39;Connected!&#39;);
});

Here's the code in Flutter:<br>

import &#39;package:flutter/material.dart&#39;;
import &#39;package:flutter/foundation.dart&#39;;
import &#39;package:flutter/services.dart&#39;;
import &#39;package:web_socket_channel/io.dart&#39;;
import &#39;package:connectivity/connectivity.dart&#39;;
import &#39;package:web_socket_channel/web_socket_channel.dart&#39;;

class MyApp extends StatelessWidget
{
  @override
  Widget build(BuildContext context)
  {
    final title = &#39;LumenApp Prototype&#39;;
    IOWebSocketChannel channel;
    try
    {
      channel = new IOWebSocketChannel.connect(&#39;wss://xxxxxxxx.xxx.xxx:xxxx/&#39;);
      MyHomePageState.noResponse = false;
    }
    catch(e)
    {
      MyHomePageState.noResponse = true;
    }
    return MaterialApp(
      title: title,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        primaryTextTheme: TextTheme(
          title: TextStyle(
            color: Colors.yellow[600],
          ),
        ),
      ),
      home: MyHomePage(
        title: title,
        channel: channel,
      ),
    );
  }
}

The error on Flutter is: WebSocketChannelException: WebSocketChannelException: HandshakeException: Handshake error in client (OS Error: CERTIFICATE_VERIFY_FAILED: self signed certificate(handshake.cc:354))

This happens inside this function:

  void initPlatformState()
  {
    widget.channel.stream.listen((message)
    {
      setState(() { noResponse = false; });
      //Handle message...
    },
    onError: (error)
    {
      print(error);
      if(mounted)
      {
        setState((){ noResponse = true;});
      }
    },
    onDone: ()
    {
      if(mounted)
      {
        setState((){ noResponse = true; });
      }
    });
  }

I used a self-signed certificate server-side made with openssl.<br>
Any idea how to solve this?

答案1

得分: 1

如果您偶然遇到了这个GitHub帖子,您可以按照此评论中的临时解决方法进行操作:

class MyHttpOverrides extends HttpOverrides {
  @override
  HttpClient createHttpClient(SecurityContext context) {
    return super.createHttpClient(context)
      ..badCertificateCallback = (X509Certificate cert, String host, int port) => true;
  }
}

void main() {
  HttpOverrides.global = new MyHttpOverrides();
  runApp(new MyApp());
}

它适用于具有自签名证书的本地IP。

为了详细说明,这里是相同的解决方案

仅为了清晰起见,特别是对于Flutter/Dart的新手,以下是在项目中全局启用此选项所需执行的操作:

  1. 在您的main.dart文件中,添加或导入以下类:
class MyHttpOverrides extends HttpOverrides {
  @override
  HttpClient createHttpClient(SecurityContext? context) {
    return super.createHttpClient(context)
      ..badCertificateCallback = (X509Certificate cert, String host, int port) => true;
  }
}
  1. 在您的main函数中,在函数定义之后添加以下行:
HttpOverrides.global = MyHttpOverrides();

这个评论对通过这个问题非常有帮助,请注意...

这应该在开发模式下使用,请在要发布到生产时不要这样做,这个答案的目的是使开发对您来说更容易一些,对于生产,您需要修复您的证书问题并正确使用它,请查看其他答案,因为它可能对您的情况有所帮助。

值得一提的是,现在可以免费获得签名证书(https://letsencrypt.org/)。

此外,我认为Flutter团队正在努力完善文档,以更好地参考此问题。它正在这里跟踪

英文:

If you happen to bumped in this GitHub post, you can follow the temporary fix from this comment:

> class MyHttpOverrides extends HttpOverrides{
> @override
> HttpClient createHttpClient(SecurityContext context){
> return super.createHttpClient(context)
> ..badCertificateCallback = (X509Certificate cert, String host, int port)=> true;
> }
> }
>
> void main(){
> HttpOverrides.global = new MyHttpOverrides();
> runApp(new MyApp());
> }

It works on local ip with self signed certificate.

To elaborate, here is the same solution:

> Just for the sake of clarity specially for the newcomers to
> Flutter/Dart, here is what you need to do in order to enable this
> option globally in your project:
>
> 1. In your main.dart file, add or import the following class:
>
> > class MyHttpOverrides extends HttpOverrides{ @override
&gt; &gt; HttpClient createHttpClient(SecurityContext? context){
&gt; &gt; return super.createHttpClient(context)
&gt; &gt; ..badCertificateCallback = (X509Certificate cert, String host, int port)=&gt; true; } }

>
> 2. In your main function, add the following line after function definition:
>
>
>
> > HttpOverrides.global = MyHttpOverrides();
>
>
> This
> comment was very helpful to pass through this matter, and please
> note that...

>
>
> > This should be used while in development mode, do NOT do this when
> > you want to release to production, the aim of this answer is to make
> > the development a bit easier for you, for production, you need to fix
> > your certificate issue and use it properly, look at the other answers
> > for this as it might be helpful for your case.

Another thing worth mentioning, signed certificates are available for free now (https://letsencrypt.org/).

Also, I think the Flutter team is working to enhance the documentation for better reference regarding this issue. It is being tracked here.

huangapple
  • 本文由 发表于 2020年1月3日 23:12:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/59580971.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定