dio
dio copied to clipboard
Use modern Fetch API with Dio on Web
Request Statement
I am trying to figure out Dio and CORS on web. Google is used here as an example, but it could be anything.
Currently if you were to make a request with Dio to "https://www.google.com/" on web. Your request would fail with a transport error, as the browser blocks the request because Google does not reply with the header that allows the browser to do this.
This is done to prevent websites from sending requests to Google with your current cookies, which could be dangerous.
But what happens if you just want to request the page without cookies? As if you were never logged in at all. It seems that XMLHttpRequest only wants to send cookies, or not send anything at all.
Is this doable with the modern Fetch API? https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API It looks like there are different modes for cors. Possibly one with this effect?
If so than should there be an option to use this modern Fetch API with Dio? Especially when modern Fetch API allows for streaming, which is not possible with XMLHttpRequest.
Solution Brainstorm
No response
In the meantime, you're able to write your own adapter, which makes use of fetch instead of xhr. If you happen to do so, we would appreciate a PR.
If we work on this, we should check for browser compatibility before starting.
Regarding the Fetch API, I just found a new plugin that integrates the Fetch API for the http
package. https://pub.dev/packages/fetch_client
We recently received many requests related to obtaining streams directly on the Web platform. This might have a higher priority to implement as a new Dio instance or adapter.
Related:
- #1795
- #1621
- #1279
Theoretically, you could wrap the http fetch_client
in the ConversionLayerAdapter to enable it easily.
The ConversionLayerAdapter could maybe its own package to allow an easy interopt between http and dio
You can directly use fetch_client
's underlying fetch_api
to get strong typed bindings.
it is necessary to add in ConversionLayerAdapter or make another layer like that with another name or should we directly add to browser_adapter
@meetdhanani17 I'm not sure, I understand what you're trying to say.
Right now, you can't use the ConversionLayerAdapter outside of the native_dio_adapter
, but it could be moved into its own package, to allow an easier interopt between dio
and http
packages. It should not be moved into dio, since it would add a dependency on http
.
hi, i have used ConversionLayerAdapter to solve “Web Environment cannot obtain real-time stream”,but it doesn't work, it still return the result by one time, here is my example, please help me figure out what i am wrong:
Map<String, dynamic> bodyWrap = {'params': body};
RequestOptions options =
RequestOptions(method: "post",contentType: "application/json",responseType: ResponseType.stream);
options.headers = ChatHttpUtil.getInstance().getDefaultHead();
options.data = json.encode(bodyWrap);
options.baseUrl = "http://test-inside-city-ai-assistant.songguo7.com/";
options.path = "city-ai-assistant/backend/chat/sse/send/v2";
final cla = ConversionLayerAdapter(BrowserClient());
final response = await cla.fetch(
options,
null,
null,
);
if (response.statusCode == 200 || response.statusCode == 201) {
ChatData chatData = ChatData(false, [], "", 0);
ctx.state.chatDataList.add(chatData);
Stream<Uint8List> stream = response.stream;
stream.listen((event) {
print("receiver event");
Uint8List uint8list = event;
String string = utf8.decode(uint8list);
List<String> items = string.split("data:");
print("List<String> items=$items");
items.forEach((element) {
element = element.trim();
if (element.startsWith("{") && element.endsWith("}")) {
Map<String, dynamic> map = jsonDecode(element);
element = element.replaceAll("\n", '\\n');
ChatBaseInfo chatBaseInfo = ChatBaseInfo.fromJson(map);
if (chatBaseInfo.code == 200) {
ctx.state.chatDataList.last.messageId =
chatBaseInfo.data!.messageId;
ctx.state.sessionId = chatBaseInfo.data!.sessionId!;
handleData(
chatBaseInfo.data!.content!, ctx.state.chatDataList.last);
if ("stop" == chatBaseInfo.data!.finishReason) {
ctx.state.isSendingMessage = false;
}
} else {
ctx.state.chatDataList.last.infos
.add(ChatInfo(1, text: chatBaseInfo.message));
ctx.state.isSendingMessage = false;
}
ctx.dispatch(ChatActionCreator.onUpdate());
}
});
});
Can you please properly format your example? It's hard to understand without formatting. Typically, you need to do something like this (pseudo code):
final dio = Dio();
dio.adapter = ConversionLayerAdapter(FetchClient()); // from https://pub.dev/packages/fetch_client
final response = await dio.get(...);
Please note that I haven't tested the code and it's from memory so names may be slightly off
Can you please properly format your example? It's hard to understand without formatting. Typically, you need to do something like this (pseudo code):
final dio = Dio(); dio.adapter = ConversionLayerAdapter(FetchClient()); // from https://pub.dev/packages/fetch_client final response = await dio.get(...);
Please note that I haven't tested the code and it's from memory so names may be slightly off
i am sorry ,i'm not familiar with the format, now i use "BrowserClient" instead of "FetchClient",am i wrong?
The BrowserClient
doesn't use the fetch API as far as I know.
thanks for your reply, Could you provide me a complete use case?
must i use FetchClient ?
Unfortunately, you have to figure that out yourself since I haven't tested or tried anything myself, but the example above should get you there.
thank you, now i try with FetchClient to solve the issue.
Can you please properly format your example? It's hard to understand without formatting. Typically, you need to do something like this (pseudo code):
final dio = Dio(); dio.adapter = ConversionLayerAdapter(FetchClient()); // from https://pub.dev/packages/fetch_client final response = await dio.get(...);
Please note that I haven't tested the code and it's from memory so names may be slightly off
at last, i resolve the issue with ConversionLayerAdapter(FetchClient(mode: RequestMode.cors))
, thanks again.