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

Flutter Web如何获取XMLHttpRequest错误详情?

针对你在Flutter Web + graphql-flutter中遇到的底层错误区分问题,可以通过拆解异常链+Web平台原生HttpRequest信息来精准判断错误类型,下面是具体实现方案:

错误类型区分思路

graphql-flutter的错误层级为:OperationException → LinkException → Web平台原生ProgressEvent。像连接超时、连接拒绝这类底层网络错误,实际藏在LinkException.originalException对应的ProgressEvent里,我们可以通过这个事件关联的HttpRequest对象获取更细节的错误信息。

具体实现代码

先通过条件导入Web平台的dart:html库(避免跨平台编译问题),再编写错误判断工具类:

import 'package:graphql_flutter/graphql_flutter.dart';
// 条件导入Web平台专属库,非Web平台会导入dart:io占位
import 'dart:html' if (dart.library.io) 'dart:io' as platform;

// 定义错误类型枚举,方便后续区分处理
enum GraphQLErrorType {
  connectionRefused,
  timeout,
  unknownHost,
  httpError, // 带HTTP状态码的错误,如401、500
  graphQLError, // 服务端返回的GraphQL业务错误
  unknown,
}

GraphQLErrorType getGraphQLErrorType(QueryResult result) {
  if (!result.hasException) {
    return GraphQLErrorType.unknown;
  }

  final exception = result.exception;
  // 优先处理GraphQL业务错误(非网络层错误)
  if (exception?.graphqlErrors.isNotEmpty == true) {
    return GraphQLErrorType.graphQLError;
  }

  // 处理网络/链路层面的错误
  final linkException = exception?.linkException;
  if (linkException != null) {
    final originalException = linkException.originalException;
    // Web平台下,originalException是ProgressEvent类型
    if (originalException is platform.ProgressEvent) {
      final request = originalException.target as platform.HttpRequest;
      
      // 连接拒绝、未知主机这类无有效HTTP状态码的错误,request.status会是0
      if (request.status == 0) {
        final error = request.error;
        if (error != null) {
          final errorMsg = error.toString().toLowerCase();
          // 匹配不同浏览器的错误信息关键字
          if (errorMsg.contains('connection refused')) {
            return GraphQLErrorType.connectionRefused;
          } else if (errorMsg.contains('timeout')) {
            return GraphQLErrorType.timeout;
          } else if (errorMsg.contains('unknown host') || errorMsg.contains('dns')) {
            return GraphQLErrorType.unknownHost;
          }
        }
        return GraphQLErrorType.unknown;
      } else {
        // 有正常HTTP状态码的错误,归类为HTTP错误
        return GraphQLErrorType.httpError;
      }
    }
  }

  return GraphQLErrorType.unknown;
}

// 示例:判断是否为连接拒绝错误
bool isConnectionRefused(QueryResult result) {
  return getGraphQLErrorType(result) == GraphQLErrorType.connectionRefused;
}

// 整合你原有的401判断逻辑
bool isGraphqlResultUnauthorized(QueryResult result) {
  if (getGraphQLErrorType(result) != GraphQLErrorType.httpError) {
    return false;
  }
  final linkException = result.exception?.linkException;
  if (linkException is HttpLinkParserException) {
    return linkException.response.statusCode == 401;
  }
  return false;
}

注意事项

  1. 浏览器兼容性:不同浏览器对底层错误的描述文本有差异,比如Chrome的连接拒绝错误是net::ERR_CONNECTION_REFUSED,Firefox是NetworkError: Connection refused,所以用关键字模糊匹配更稳妥。
  2. 跨平台兼容:如果应用需要支持移动端,必须用条件导入dart:html,否则非Web平台会编译报错。
  3. GraphQL业务错误区分:这类错误是服务端返回的业务逻辑错误(如参数非法、权限不足),会存放在OperationException.graphqlErrors中,可单独做业务处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 22:20:11