繁体   English   中英

aws appsync 订阅不适用于 flutter graphql_flutter package

[英]aws appsync subscription not working with flutter graphql_flutter package

我的 pubspec.yaml

dev_dependencies:
  flutter_test:
    sdk: flutter
  graphql_flutter: ^4.0.0

roomctrl.dart

import 'package:flutter/material.dart';
import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:innospace/config/appsync-service.dart';
import 'package:innospace/config/client_provider.dart';

class RoomCtrl extends StatefulWidget {
  RoomCtrl({Key key}) : super(key: key);

  _RoomCtrlState createState() => _RoomCtrlState();
}

class _RoomCtrlState extends State<RoomCtrl> {

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return ClientProvider(
        child: Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
         Subscription(
        options:SubscriptionOptions(
            document: gql(AppSyncService.onUpdateStateTestSubscription)),
          builder: (result) {
            if (result.hasException) {
              return Text(result.exception.toString());
            }

            if (result.isLoading) {
              return Center(
                child: const CircularProgressIndicator(),
              );
            }
            return Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: <Widget>[
                  Container(
                    child: Text(result.data.length.toString()),
                  )
                ],
              ),
            );
          },
        )

          ],
        ),
      ),
    ));
  }
}

client_provider.dart

import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:flutter/material.dart';

import 'constants.dart';

String uuidFromObject(Object object) {
  if (object is Map<String, Object>) {
    final String typeName = object['__typename'] as String;
    final String id = object['id'].toString();
    if (typeName != null && id != null) {
      return <String>[typeName, id].join('/');
    }
  }
  return null;
}

ValueNotifier<GraphQLClient> clientFor() {
   const dynamic headers = {
    "headers": {
      "host": AWS_APP_SYNC_ENDPOINT_AUTHORITY,
      "x-api-key": AWS_APP_SYNC_KEY
    }};
   const  sClient= SocketClientConfig(
      autoReconnect : true,
      initialPayload: headers
  );

   final WebSocketLink _webSocketLink =new WebSocketLink(AWS_APP_SYNC_ENDPOINT_WSS,  config:sClient );

   final Link link = _webSocketLink;
  return ValueNotifier<GraphQLClient>(
    GraphQLClient(
      cache: GraphQLCache(),
      link: link,
    ),
  );
}

/// Wraps the root application with the `graphql_flutter` client.
/// We use the cache for all state management.
class ClientProvider extends StatelessWidget {
  ClientProvider({
    @required this.child,
  }) : client = clientFor();

  final Widget child;
  final ValueNotifier<GraphQLClient> client;

  @override
  Widget build(BuildContext context) {
    return GraphQLProvider(
      client: client,
      child: child,
    );
  }
}

常量.dart

[https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html][1]

const AWS_APP_SYNC_ENDPOINT_AUTHORITY = "xxxxxxxxxxxxxxxxxxxxx.appsync-api.ap-southeast-2.amazonaws.com"; 
const AWS_APP_SYNC_ENDPOINT_WSS = "wss://xxxxxxxxxxxxxxxxxxxxx.appsync-realtime-api.ap-southeast-2.amazonaws.com/graphql?header=base64encryption(xxx-xxxxxxxxxxxxxxxxxx as per aws)&payload=e30="; 
const AWS_APP_SYNC_KEY = "xxx-xxxxxxxxxxxxxxxxxx";

订阅查询

static String onUpdateStateTestSubscription = '''
        subscription OnUpdateStateTest {
        onUpdateStateTest {
          __typename
          RoomId
          RoomName
        }
      }''';

安慰

Connecting to websocket: wss://xxxxxxxxxxxxxxxxxxxxx.appsync-realtime-api.ap-southeast-2.amazonaws.com/graphql?header=base64encryption(xxx-xxxxxxxxxxxxxxxxxx as per aws)&payload=e30=...
I/flutter ( 9942): Connected to websocket.
I/flutter ( 9942): Haven't received keep alive message for 30 seconds. Disconnecting..
I/flutter ( 9942): Disconnected from websocket.
I/flutter ( 9942): Scheduling to connect in 5 seconds...
I/flutter ( 9942): Connecting to websocket: wss://xxxxxxxxxxxxxxxxxxxxx.appsync-realtime-api.ap-southeast-2.amazonaws.com/graphql?header=base64encryption(xxx-xxxxxxxxxxxxxxxxxx as per aws)&payload=e30=...
I/flutter ( 9942): Connected to websocket.
I/flutter ( 9942): Haven't received keep alive message for 30 seconds. Disconnecting..
I/flutter ( 9942): Disconnected from websocket.
I/flutter ( 9942): Scheduling to connect in 5 seconds...

最后,移动设备上的 output 显示正在加载 gif,即 CircularProgressIndicator(),意味着在“if (result.isLoading)”处始终返回 true

[![在此处输入图像描述][2]][2]

谁能帮忙!!

注意:相同的 appsync 在 angular 应用程序中完美运行。 [1]: https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html [2]: https://i.stack.imgur.com/59KZh.png

在底部查看我最近的更新。

我实际上遇到了同样的问题。 我没有完整的答案,但我觉得这是部分答案的线索。

从链接

据我所知,AppSync 不使用 wss://<your_end_point>。 我以前试过这个,我的 http 连接从未“升级到 wss”连接。 我必须向 http 端点发送请求订阅连接的请求,然后 AWS 返回包含新端点(wss url)、主题和客户端 ID 的连接详细信息。 只有这样我才能使用第三方库连接到套接字(使用返回的 URL AWS)。 我不得不深入研究他们的官方 sdk 来找出这个问题,然后通过反复试验让它工作。

我已经使用 GraphiQL 工具确认,当我发布订阅 graphql blob 时确实会收到响应。 我得到了 websocket url 和 JSON 中的其他一些项目。 我还没有想出如何在 Flutter 中捕获该响应,但如果我也找到该部分,我会更新它。

从那里,我相信我们需要从新的 url 动态创建 websocket 并将我们的订阅 graphql blob 发送给它。

绝对,这是令人费解的,但这是我现在要走的路。

更新:适用于 Flutter 的 AWS Amplify 现在支持订阅。 我正在使用混合解决方案。 我有用于突变/查询的flutter_graphqlartemis 对于订阅,我使用的是amplify_api: '<1.0.0' 它在过去几周刚刚发布。 实际上,我只花了几分钟就让它工作了。 Amplify 会自动为您执行 URL 解析和身份验证。

链接到官方文档

您需要生成特定于您的 AWS 终端节点的amplifyconfiguration.dart并将其添加到您的项目中。 AWS 文档涵盖了这一点,设置您的 AWS 终端节点的人应该确切地知道您需要什么。

来自链接的示例:

try {
    String graphQLDocument = '''subscription OnCreateTodo {
        onCreateTodo {
          id
          name
          description
        }
      }''';

    var operation = Amplify.API.subscribe(
        request: GraphQLRequest<String>(document: graphQLDocument),
        onData: (event) {
          print('Subscription event data received: ${event.data}');
        },
        onEstablished: () {
          print('Subscription established');
        },
        onError: (e) {
          print('Subscription failed with error: $e');
        },
        onDone: () {
          print('Subscription has been closed successfully');
        });
} on ApiException catch (e) {
    print('Failed to establish subscription: $e');
}

不要忘记取消订阅:

// Cancel the subscription when you're finished with it
operation.cancel();

我在这里尝试的第一件事是使用@JLuisRojas 的自定义 AppSync 请求序列化程序:

class AppSyncRequest extends RequestSerializer {
  final Map<String, dynamic> authHeader;

  const AppSyncRequest({
    this.authHeader,
  });

  @override
  Map<String, dynamic> serializeRequest(Request request) => {
    "data": jsonEncode({
      "query": printNode(request.operation.document),
      "variables": request.variables,
    }),
    "extensions": {
      "authorization": this.authHeader,
    }
  };
}

// ...

final token = session.getAccessToken().getJwtToken();

String toBase64(Map data) => base64.encode(utf8.encode(jsonEncode(data)));

final authHeader = {
  "Authorization": token,
  "host": "$apiId.appsync-api.$zone.amazonaws.com",
};

final encodedHeader = toBase64(authHeader);

final WebSocketLink wsLink = WebSocketLink(
  'wss://$apiId.appsync-realtime-api.$zone.amazonaws.com/graphql?header=$encodedHeader&payload=e30=',
  config: SocketClientConfig(
    serializer: AppSyncRequest(authHeader: authHeader),
    inactivityTimeout: Duration(seconds: 60),
  )
);

final AuthLink authLink = AuthLink(
  getToken: () => token,
);

final Link link = authLink.concat(wsLink);

请注意,连接似乎不仅需要header查询参数,而且还需要在每个请求的extensions字段中授权,以及非标准编码结构 ( docs )。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM