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

Flutter Web实现SSL证书固定(SSL Pinning)遇问题求助

Flutter Web 自定义PEM证书SSL通信解决方案

问题根源

Flutter Web运行在浏览器沙箱内,受浏览器安全策略限制,无法直接控制SSL证书验证逻辑:

  • SecurityContext是dart:io专属API,Web环境完全不支持,这是你第一个代码报错的原因。
  • Dio在Web环境下默认使用BrowserHttpClientAdapter,它基于浏览器原生的fetch/XMLHttpRequest实现,无法像原生平台的DefaultHttpClientAdapter那样自定义证书验证规则。

可行解决方案

方案1:使用浏览器信任的证书(生产环境推荐)

  • 如果是正式环境,直接让目标服务器使用主流CA机构签发的SSL证书,浏览器会自动信任,无需额外代码配置。
  • 测试环境下,可将自签证书手动添加到测试浏览器的信任根证书列表(不同浏览器操作路径不同,例如Chrome:设置→隐私和安全→安全→管理证书→导入证书)。

方案2:通过后端代理转发请求(必须用自定义证书的场景)

由于浏览器无法直接自定义SSL验证逻辑,只能通过中间后端服务处理证书校验,Flutter Web请求代理服务器,再由代理转发到目标服务器:

  1. 搭建后端代理服务(以Dart为例):
import 'dart:io';

void main() async {
  // 启动本地代理服务
  final server = await HttpServer.bind(InternetAddress.anyIPv4, 8080);
  print('Proxy server running on http://localhost:8080');

  await for (final request in server) {
    try {
      // 加载自定义PEM证书
      final certBytes = await File('assets/certificates/bankid/cert.pem').readAsBytes();
      final securityContext = SecurityContext(withTrustedRoots: false);
      securityContext.setTrustedCertificatesBytes(certBytes);

      // 创建带自定义证书的HttpClient
      final client = HttpClient(context: securityContext);
      // 构造目标服务器请求地址
      final targetUri = Uri.parse('https://appapi2.test.bankid.com${request.uri}');
      final proxyRequest = await client.open(
        request.method,
        targetUri.host,
        targetUri.port,
        targetUri.path + (targetUri.query.isNotEmpty ? '?${targetUri.query}' : ''),
      );

      // 复制原请求头
      request.headers.forEach((key, value) => proxyRequest.headers.add(key, value));
      // 转发请求体
      await request.pipe(proxyRequest);
      // 获取目标服务器响应
      final proxyResponse = await proxyRequest.close();

      // 配置跨域允许(必须)
      request.response.headers.add('Access-Control-Allow-Origin', '*');
      request.response.headers.add('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
      request.response.headers.add('Access-Control-Allow-Headers', '*');

      // 转发响应给Flutter Web
      await proxyResponse.pipe(request.response);
    } catch (e) {
      print('Proxy error: $e');
      request.response.statusCode = HttpStatus.internalServerError;
      await request.response.close();
    }
  }
}
  1. Flutter Web端修改请求地址为代理服务器:
// Dio示例
void bid() async {
  final dio = Dio();
  try {
    // 请求代理服务器,而非直接请求目标地址
    var response = await dio.get('http://localhost:8080/rp/v5.1');
    print(response.data);
  } catch (error) {
    if (error is DioError) {
      print(error.toString());
    } else {
      print('Unexpected Error');
    }
  }
}

// HttpClient示例
fetchData()async{
  final response = await http.get(Uri.parse('http://localhost:8080/rp/v5.1'));
  print(response.body);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 09:30:54