Flutter Web 集成测试 CORS XMLHttpRequest 错误

Sup*_*ive 5 testing http cors flutter flutter-web

我正在本地为 Web 运行 Flutter 集成测试。这是一个示例集成测试,其中我唯一要做的就是按下按钮 ping https://google.com,然后在收到响应后完成。

当我在本地运行这个集成测试时,我收到一个XMLHttpRequest错误。这可能是 CORS 错误,但我不确定是不是这种情况。

如何在集成测试中为不属于我的网站发出 HTTP 请求?

颤振版本:

Flutter 2.2.0 • channel stable • https://github.com/flutter/flutter.git
Framework • revision b22742018b (12 days ago) • 2021-05-14 19:12:57 -0700
Engine • revision a9d88a4d18
Tools • Dart 2.13.0
Run Code Online (Sandbox Code Playgroud)

错误:

??? EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ??????????????????
The following ClientException was thrown running a test:
XMLHttpRequest error.

When the exception was thrown, this was the stack:
dart-sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart 909:28 get current
...
Run Code Online (Sandbox Code Playgroud)

cre*_*not 8

为什么会出现这种情况?

\n

正如您所说,您正在尝试ping,即发出 HTTP 请求,以https://www.google.com进行Web 集成测试

\n

在网络上运行任何内容时,网络安全都适用。在 Web 安全模型中,安全性是由浏览器引擎使用 同源策略来强制执行的,这本质上涉及浏览器引擎阻止前端 JavaScript 对跨源请求响应的访问。但可以通过使用跨源资源共享 (CORS)来克服这种阻塞,这是服务器告诉浏览器它们明确允许跨源访问的一种方式。
\n这通常是使用Access-Control-Allow-Origin标头完成的来完成的。

\n

localhost由于您的集成测试将始终在任何外部 HTTP 请求上运行将是跨域的。

\n

跨域资源共享示例

\n

让我们检查一下https://www.google.com,这是您的示例:

\n

google.com GET 请求

\n

正如你所看到的,你看不到它。是的,没有Access-Control-Allow-Origin发送响应头google.com

\n

\xe2\x86\x92 这意味着根据网络安全,您不允许提出此请求不允许从不同的域(跨域)

\n

它与 Web 集成测试有什么关系吗?

\n

现在,问题可能会出现“为什么相同的集成测试可以在移动设备上工作”。
\n是的,这是一个好问题,答案很简单。CORS 策略仅存在于 Web 上,即它们实际上仅存在于浏览器内部。这是因为任何人都可以在网络上注入任何代码(本质上)。然而,在移动设备上,请求是安全的,这就是为什么您可以提出任何您想要的请求 - 在网络上则不能。

\n
\n

Flutter Web 集成测试将在 Chrome 实例内运行,这是有道理的。集成测试的重点是模拟真实行为,即查看组件是否协同工作以及 Flutter 的情况integration_test(在某种程度上更接近自动化 e2e 测试),这意味着测试应用程序是否能够成功工作在网络平台上。

\n

\xe2\x86\x92 想想看,以这种方式进行集成测试也是最有意义的,因为相同的请求在真正的 Web 应用程序中也会失败。

\n

和颤振有关系吗?

\n

,绝对不!事实上,没有框架,没有办法避免这种情况,因为这是有意的。一般来说,网络平台都有这些安全策略,您必须处理它们。

\n

这意味着任何 Web 应用程序都无法发出 HTTP 请求(截至 2021 年 5 月 27 日),https://www.google.com除非它实际上在同一域上运行。

\n
\n

我们可以使用 Chrome 的 JS 控制台快速可视化这一点,并https://www.google.com从控制台进行 ping,一次是在随机网站上,一次是实际在 Chrome 上。

\n

Ping google.com

\n

可以看到,在JS控制台中请求甚至失败了。您可能认为控制台具有特权,但即使如此,请求也会失败,除非您位于同一源(左侧)。
\n请注意,错误消息中指定了不同的策略/标头。这将根据所使用的浏览器而有所不同,并且与参数/理解无关。

\n

解决方案

\n

既然我们已经确定这实际上是预期的行为,那么我们如何正确地进行此操作,如何使其发挥作用?

\n

使用正确的资源

\n

你的测试失败了,因为它应该失败。在网络上,您无法访问您想要的域。但是,如果您使用实际上允许这样做的一个呢?

\n

当然,有许多站点实际上允许 CORS,即允许从外部源访问。在这里您可以看到响应标头https://i.imgur.com/MQdD3lg.png

\n

i.imgur 请求

\n

Imgur 提供用于共享的图像,因此他们从逻辑上希望允许这些图像嵌入到任何网站或网络应用程序中。这就是为什么你可以看到:

\n
access-control-allow-origin: *\n
Run Code Online (Sandbox Code Playgroud)\n

这意味着可以从任何地方请求图像

\n

\xe2\x86\x92 我建议您在集成测试中使用它来 ping ;)

\n

这不是一个错误

\n

为了强调这是 100% 预期的行为,我们需要回答这个问题通常是如何解决的。

\n

好吧,如果您托管资源,您将是设置响应标头的人。为了调试测试目的所做的就是指定localhost允许访问的

\n

添加 CORS 标头

\n

例如,如果您想运行本地调试和测试,您将需要指定要运行的端口。在 Flutter 中,这是通过--web-port参数完成的。localhost:4200您可以使用来运行测试--web-port 4200
\n现在,您需要将此本地主机端口添加到响应标头中允许的来源。有关如何执行此操作的示例,请参阅这篇 Google Cloud 文章

\n

在 Chrome 中禁用网络安全

\n

我不建议做的是完全禁用Web 安全性的方法(因为它与集成测试应涵盖的真实场景不同)。如果这样做,您可以忽略所有 Web 安全策略并运行您想要的任何请求。

\n

由于 Flutter Web 集成测试是在 Chrome 上运行的,因此您可以--disable-web-security在 Chrome 设备上使用来禁用 Web 安全性。

\n