由于CORS,使用http包的Flutter Web请求失败

vh0rcniy  于 2023-05-19  发布在  Flutter
关注(0)|答案(1)|浏览(154)

背景

我正在使用GitHub Codespaces,它为本地托管的应用程序进行端口转发。因此,当我运行flutter run -d web-server --web-hostname 127.0.0. --web-port时,localhost URL将被镜像为githubpreview.dev URL。
在客户端,我有一个函数来测试与数据库的连接:

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"
      },
    );

_httpClientHttpClient()的 Package 器。在服务器端,我有如下功能:

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);
}

问题

每当运行testConnection时,请求都会成功发送,因为服务器会记录传入的请求,但客户端没有收到服务器发送的响应,并返回XMLHttpRequestError。现在,我在编写Flutter Web应用程序时多次遇到这个错误,但这个错误让我很困惑。Postman可以正确接收数据,所以我很确定CORS是这个问题的罪魁祸首。

其他信息

Flutter刮刀输出:

[✓] 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.

如何解决此问题?

nsc4cvqm

nsc4cvqm1#

对于那些想知道如何解决这个问题的人,我使用了dart:html中的HttpRequest.requestCrossOrigin,而不是http包中的HttpClient

示例代码

每当跨源请求被阻止时,通常是因为来自服务器的响应没有正确的CORS权限,并且在到达客户端之前被浏览器阻止。为了解决这个问题,我们需要在服务器代码中添加以下头文件(在我的例子中是server.js):

function options(origin) {
    return {
        "headers": {
            "Content-Type": "application/json",
            "Access-Control-Allow-Origin": origin,
            "Access-Control-Allow-Credentials": true,
        },
        "body": {
            ...
        }
    }
}

这会为服务器的每个请求生成一个模板响应,该响应在CORS权限中启用请求的起源。然后,可以在端点代码的其余部分中修改该响应,以将有效载荷添加到body等等。
接下来,服务器中的端点如下所示:

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);
}

除此之外,我们现在对客户端进行编码。请注意**此解决方案仅适用于Flutter Web应用程序,因为它使用dart:html,这是一组仅适用于Web平台的服务。
我们的.dart文件包含以下代码,用于发送带有JSON正文的POST请求:

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,在控制台中得到如下结果:

{"status":{"code":200,"msg":"All ok!"},"payload":[{"a":1,"b":[2,3,4],"c":true}]}

希望这有帮助!

相关问题