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

Flutter中使用Ferry获取GraphQL响应头的方法求助

在Ferry中获取GraphQL响应头/Cookie里的Token

问题场景

使用Ferry向GraphQL服务器发起查询时,需要从响应头或Cookie中提取access token和refresh token,但发现OperationResponse没有提供访问响应头的属性,无法直接获取目标信息。

当前代码:

@override
Stream<OperationResponse<TData, TVars>> request<TData, TVars>(
    OperationRequest<TData, TVars> request) {
  try {
    Stream<OperationResponse<TData, TVars>> response = _client.request<TData, TVars>(request);
    response.first.then((requestResponse) {
        final headers = requestResponse // 此处找不到获取headers的途径
      
      final authorization = headers?['authorization']?.firstOrNull;
      final cookie = headers?['set-cookie']?.firstOrNull;

      if (authorization != null) {
        _authToken = authorization;
        _securedStorageService.saveAuthToken(authorization);
      }

      if (cookie != null) {
        _refreshToken = cookie;
        _securedStorageService.saveRefreshToken(cookie);

        final maxAge = cookie.split(';').firstWhere(
          (element) => element.contains('Max-Age'),
          orElse: () => '',
        );

        if (maxAge.isNotEmpty) {
          final expirationSeconds = maxAge.split('=').last;
          final expires = DateTime.now().add(Duration(seconds: int.parse(expirationSeconds)));
          _tokenExpired = expires.isBefore(DateTime.now());
          _securedStorageService.saveRefreshTokenExpiration(expires.toIso8601String());
        }
      }

      return requestResponse;
    });
    return response;
  } catch (e) {
    rethrow; // 错误交给上层仓库层处理
  }
}

解决方案

Ferry的OperationResponse本身不会携带原始HTTP响应头,需要通过自定义Link拦截响应来提取头信息。Link是Ferry处理请求/响应的核心链路,HttpLink会把响应头存在HttpLinkResponseContext中,我们可以在自定义Link里取出这些信息。

创建一个继承自Link的类,在request方法中拦截响应并提取头:

class HeaderExtractionLink extends Link {
  final SecuredStorageService _securedStorageService;
  String? _authToken;
  String? _refreshToken;
  bool _tokenExpired = false;

  HeaderExtractionLink(this._securedStorageService);

  @override
  Stream<Response> request(
    Request request, [
    NextLink? forward,
  ]) async* {
    // 转发请求到下一个Link(通常是HttpLink)
    final responseStream = forward!(request);
    
    await for (final response in responseStream) {
      // 从响应上下文获取HTTP头
      final httpContext = response.context.entry<HttpLinkResponseContext>();
      final headers = httpContext?.headers;
      
      if (headers != null) {
        // 提取Authorization头
        final authorization = headers['authorization']?.firstOrNull;
        if (authorization != null) {
          _authToken = authorization;
          await _securedStorageService.saveAuthToken(authorization);
        }

        // 提取Set-Cookie头
        final cookie = headers['set-cookie']?.firstOrNull;
        if (cookie != null) {
          _refreshToken = cookie;
          await _securedStorageService.saveRefreshToken(cookie);

          // 解析Cookie的Max-Age
          final maxAge = cookie.split(';').firstWhere(
            (element) => element.contains('Max-Age'),
            orElse: () => '',
          );

          if (maxAge.isNotEmpty) {
            final expirationSeconds = maxAge.split('=').last;
            final expires = DateTime.now().add(Duration(seconds: int.parse(expirationSeconds)));
            _tokenExpired = expires.isBefore(DateTime.now());
            await _securedStorageService.saveRefreshTokenExpiration(expires.toIso8601String());
          }
        }
      }
      
      // 将响应继续传递下去
      yield response;
    }
  }
}

步骤2:将自定义Link加入Ferry Client链路

初始化Ferry Client时,把自定义Link和HttpLink串联起来:

// 创建HttpLink
final httpLink = HttpLink('你的GraphQL服务器地址');
// 创建自定义的Header提取Link
final headerExtractionLink = HeaderExtractionLink(securedStorageService);

// 初始化Ferry Client,串联链路
final client = Client(
  link: headerExtractionLink.concat(httpLink),
  cache: Cache(),
);

关键说明

  • Ferry的链路是链式处理的,自定义Link会先拦截响应,提取头信息后再把响应传递给后续链路,最终生成OperationResponse。
  • HttpLinkResponseContext是HttpLink添加到响应上下文中的对象,里面包含了原始的HTTP响应头、状态码等信息。
  • 不需要再在原来的request方法中尝试提取头,自定义Link会自动处理所有请求的响应头。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 00:45:12