Reputation: 87
I am using GitHub Codespaces, which does port forwarding for locally-hosted applications. So when I run flutter run -d web-server --web-hostname 127.0.0. --web-port
the localhost URL is mirrored with a githubpreview.dev
URL.
On the client side, I have a function to test the connection with the database:
static Future<bool> testConnection() async {
http.Response response = await _httpClient.get(
Uri.parse(baseUrl + 'test'), // requestObject.slug.string
headers: {
HttpHeaders.authorizationHeader: 'Bearer 69',
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Headers":
"Origin,Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,locale",
"Access-Control-Allow-Methods": "GET, POST, PUT, PATCH, DELETE, OPTIONS"
},
);
_httpClient
is a wrapper over HttpClient()
.
On the server side, I have the function as follows:
export function use_test(request) {
console.log(`test request:${request.headers.origin}`);
let options = {
"headers":{
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Headers":
"Origin,Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,locale",
"Access-Control-Allow-Methods":
"GET, POST, PUT, PATCH, DELETE, OPTIONS"
},
"body": {
"payload": {
"msg": request['headers']
}
}
};
return ok(options);
}
Whenever testConnection
is run, the request is sent successfully, since the server logs the incoming request, but the response sent by the server is not received by the client, failing with an XMLHttpRequestError
. Now, I have come across this error many times when writing Flutter Web applications, but this one stumps me. Postman can receive the data all right, so I'm pretty sure CORS is to blame for this issue.
Flutter doctor output:
[✓] Flutter (Channel master, 3.1.0-0.0.pre.1354, on Debian GNU/Linux 11 (bullseye) 5.4.0-1074-azure, locale
en_US.UTF-8)
• Flutter version 3.1.0-0.0.pre.1354 on channel master at /workspaces/Lighthouse-Web/flutter
• Upstream repository https://github.com/flutter/flutter.git
• Framework revision a30012b275 (3 days ago), 2022-06-22 17:04:07 -0700
• Engine revision fc08bf45b0
• Dart version 2.18.0 (build 2.18.0-216.0.dev)
• DevTools version 2.14.0
[✗] Android toolchain - develop for Android devices
✗ Unable to locate Android SDK.
Install Android Studio from: https://developer.android.com/studio/index.html
On first launch it will assist you in installing the Android SDK components.
(or visit https://flutter.dev/docs/get-started/install/linux#android-setup for detailed instructions).
If the Android SDK has been installed to a custom location, please use
`flutter config --android-sdk` to update to that location.
[✗] Chrome - develop for the web (Cannot find Chrome executable at google-chrome)
! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.
[✗] Linux toolchain - develop for Linux desktop
✗ clang++ is required for Linux development.
It is likely available from your distribution (e.g.: apt install clang), or can be downloaded from
https://releases.llvm.org/
✗ CMake is required for Linux development.
It is likely available from your distribution (e.g.: apt install cmake), or can be downloaded from
https://cmake.org/download/
✗ ninja is required for Linux development.
It is likely available from your distribution (e.g.: apt install ninja-build), or can be downloaded from
https://github.com/ninja-build/ninja/releases
✗ pkg-config is required for Linux development.
It is likely available from your distribution (e.g.: apt install pkg-config), or can be downloaded from
https://www.freedesktop.org/wiki/Software/pkg-config/
[!] Android Studio (not installed)
• Android Studio not found; download from https://developer.android.com/studio/index.html
(or visit https://flutter.dev/docs/get-started/install/linux#android-setup for detailed instructions).
[✓] Connected device (1 available)
• Linux (desktop) • linux • linux-x64 • Debian GNU/Linux 11 (bullseye) 5.4.0-1074-azure
[✓] HTTP Host Availability
• All required HTTP hosts are available
! Doctor found issues in 4 categories.
How can I fix this issue?
Upvotes: 2
Views: 8807
Reputation: 87
For those wondering how to solve this problem, I used HttpRequest.requestCrossOrigin
from dart:html
instead of HttpClient
from the http
package.
Whenever a cross-origin request is blocked, it is typically because the response from the server does not have the right CORS permissions, and is blocked by the browser before reaching the client. To remedy this, we need to add in the following headers in our server code (server.js
in my case):
function options(origin) {
return {
"headers": {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": origin,
"Access-Control-Allow-Credentials": true,
},
"body": {
...
}
}
}
This generates, for each request to the server, a template response that enables the request's origin in the CORS permissions. This response can then be modified throughout the rest of the endpoint's code to add payload to the body
and such.
Next, the endpoint in the server looks like this:
export async function use_postTest(request) {
// The body of the POST request, stored as a JSON object
let reqBody = JSON.parse(await request.body.text());
// Create the template response with the incoming origin
let res = options(request.headers.origin);
// Modifying the response data
res.status = res.body.status.code = 200;
res.body.status.msg = "All ok!";
// Passing the incoming request body back to the client, to show that the POST request can be processed
res.body.payload.push(reqBody);
return response(res);
}
That aside, we now code the client. Take note that this solution is only for Flutter Web apps, since it uses dart:html
, a set of services only available for the web platform.
Our .dart
file has the following code to send POST requests with JSON bodies:
import 'dart:convert';
import 'dart:html';
Future<void> postCrossOrigin() async {
final HttpRequest request = await HttpRequest.request(
"https://...",
method: 'POST',
// the Map has to be encoded using jsonEncode
sendData: jsonEncode({
'a': 1,
'b': [2, 3, 4],
'c': true,
}),
);
// Alternatively, use jsonDecode(request.responseText) to convert the response to a native Map object
print(request.responseText);
}
flutter run -d chrome
to obtain the following result in the console:
{"status":{"code":200,"msg":"All ok!"},"payload":[{"a":1,"b":[2,3,4],"c":true}]}
Hope this helps!
Upvotes: 2