You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Dart中向使用自签名证书的HTTPS服务器提交JSON数据?

哈哈,这个问题我太熟了!我当初在开发Flutter应用对接自签名HTTPS服务器时,也踩过这个证书验证失败的坑。本质原因是Dart默认会校验服务器证书是否由受信任的CA机构颁发,而自签名证书显然不满足这个条件,所以就抛出了HandshakeException。下面给你分场景说几个靠谱的解决办法:

方法1:临时禁用证书验证(仅开发环境!)

如果你只是在本地开发测试,想快速绕开这个问题,可以直接让Dart忽略证书合法性校验。注意:绝对不能在生产环境用这个方法,会把应用暴露在中间人攻击的风险里。

用http包实现的示例代码如下:

import 'dart:io';
import 'package:http/http.dart' as http;

// 自定义一个忽略证书验证的Client
class DevHttpClient extends http.BaseClient {
  final HttpClient _innerClient = HttpClient()
    ..badCertificateCallback =
        ((X509Certificate cert, String host, int port) => true);

  @override
  Future<http.StreamedResponse> send(http.BaseRequest request) {
    return _innerClient.openUrl(request.method, request.url).then((HttpClientRequest clientReq) {
      clientReq.headers.addAll(request.headers);
      return request.finalize().pipe(clientReq).then((HttpClientResponse clientResp) {
        return http.StreamedResponse(
          clientResp.handleError((err) => throw err),
          clientResp.statusCode,
          headers: clientResp.headers,
        );
      });
    });
  }
}

// 发送POST请求的示例
void sendSecurePost() async {
  final client = DevHttpClient();
  try {
    final response = await client.post(
      Uri.parse('https://your-dev-server.com/api/submit'),
      headers: {'Content-Type': 'application/json'},
      body: '{"username": "test", "data": "sample"}',
    );
    print('请求成功,状态码:${response.statusCode}');
    print('响应内容:${response.body}');
  } catch (e) {
    print('请求出错:$e');
  } finally {
    client.close();
  }
}
方法2:将自签名证书加入信任列表(推荐开发/测试环境)

这个方法比完全禁用验证更安全——只信任你自己的自签名证书,不会随便信任其他未知证书。步骤如下:

  1. 把你的自签名证书文件(通常是.crt或.pem格式)放到Flutter项目的assets/certs目录下(没有的话自己创建)
  2. 在pubspec.yaml中配置资源路径:
flutter:
  assets:
    - assets/certs/your_self_signed_cert.crt
  1. 加载证书并创建信任该证书的HttpClient:
import 'dart:convert';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;

// 加载证书并生成安全上下文
Future<SecurityContext> getTrustedContext() async {
  // 从assets加载证书文件
  final certData = await rootBundle.load('assets/certs/your_self_signed_cert.crt');
  final certBytes = certData.buffer.asUint8List();
  
  final context = SecurityContext.defaultContext;
  context.setTrustedCertificatesBytes(certBytes);
  return context;
}

// 发送带信任证书的POST请求
void sendTrustedPost() async {
  final securityContext = await getTrustedContext();
  final client = HttpClient(context: securityContext);
  
  try {
    final request = await client.postUrl(Uri.parse('https://your-dev-server.com/api/submit'));
    request.headers.set('Content-Type', 'application/json');
    request.write(jsonEncode({'username': 'test', 'data': 'sample'}));
    
    final response = await request.close();
    final responseBody = await response.transform(utf8.decoder).join();
    
    print('请求成功,状态码:${response.statusCode}');
    print('响应内容:$responseBody');
  } catch (e) {
    print('请求出错:$e');
  } finally {
    client.close();
  }
}
方法3:生产环境的处理方案(仅内部应用适用)

如果你的应用是内部使用(比如企业内部APP),必须用自签名证书,最好的方式是让用户手动把证书安装到设备的系统信任列表中。这样Dart的HttpClient会自动识别并信任该证书,不需要修改任何代码。不过这种方式对普通用户不友好,面向大众的应用强烈建议使用CA颁发的正式证书。

最后再提醒一句:上线前一定要记得切换到受信任CA颁发的HTTPS证书,别把开发环境的配置带到生产里!

内容的提问来源于stack exchange,提问作者Rishabh Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:56:06