[英]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_graphql
和artemis
。 对于订阅,我使用的是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.