如何仅使用Dart代码解决Flutter Web API的CORS错误?

122
似乎CORS错误在网络领域是一个众所周知的问题。但这是我第一次尝试使用flutter web,我遇到了严重的错误。
下面的代码在应用版本上运行在iOS设备上时表现良好,但当我在Chrome上使用来自beta频道的Web调试测试相同的代码时,遇到了CORS错误。
其他Stack Overflow的答案解释了如何通过服务器端文件解决项目中的CORS问题,但我完全不知道什么是服务器,也不知道如何处理他们的答案。Chrome控制台的错误信息如下:
[ Access to XMLHttpRequest at 'https://kapi.kakao.com/v1/payment/ready' from origin 'http://localhost:52700' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. ]
所以,我想要做的就是仅通过Dart代码解决上述的“Access-Control-Allow-Origin header”问题!下面的代码是我尝试仅通过我的main.dart解决这些问题的内容。
onPressed: () async {
      var res =
          await http.post('https://kapi.kakao.com/v1/payment/ready', encoding: Encoding.getByName('utf8'), headers: {
        'Authorization': 'KakaoAK $_ADMIN_KEY',
        HttpHeaders.authorizationHeader: 'KakaoAK $_ADMIN_KEY',
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "POST, GET, OPTIONS, PUT, DELETE, HEAD",
      }, body: {
        'cid': 'TC0ONETIME',
        'partner_order_id': 'partner_order_id',
        'partner_user_id': 'partner_user_id',
        'item_name': 'cool_beer',
        'quantity': '1',
        'total_amount': '22222',
        'vat_amount': '2222',
        'tax_free_amount': '0',
        'approval_url': '$_URL/kakaopayment',
        'fail_url': '$_URL/kakaopayment',
        'cancel_url': '$_URL/kakaopayment'
      });
      Map<String, dynamic> result = json.decode(res.body);
      print(result);
    },

尽管我实际上已经在头部添加了"Access-Control-Allow-Origin": "*",这是大多数其他答案推荐的方法,但Chrome控制台仍然打印出相同的错误信息。奇怪的是,相同的代码在移动应用版本中可以成功请求。所以我认为这只是Flutter Web版本的问题。
希望有人能够找出问题并建议一段纯Dart代码来解决我的main.dart中的问题!

这可能是你正在寻找的解决方案 https://dev59.com/yVoU5IYBdhLWcg3wI0lN#37765371 - JLarana
使用Osman Tuzcu的答案,我创建了flutter_cors来使这个过程更加容易。 - Rexios
希望这个链接 https://dev59.com/e8Tra4cB1Zd3GeqP7XCy#72321040 能对你有所帮助 :) - Sittiphan Sittisak
30个回答

331

1- 前往 flutter\bin\cache 目录并删除名为 flutter_tools.stamp 的文件。

2- 前往 flutter\packages\flutter_tools\lib\src\web 目录并打开文件 chrome.dart

3- 查找 '--disable-extensions'

4- 添加 '--disable-web-security'


3
这个可以正常工作。谢谢。但是我收到了一个警告:“您正在使用不支持的注释行……稳定性和安全性将会受到影响。”我应该担心吗? - Becca
4
不用担心,@Becca,这只在你本地运行,没有跨域问题。 - Osman Tuzcu
4
对于Linux用户,该文件位于~/snap/flutter/common/flutter/packages/flutter_tools/lib/src/web/chrome.dart。顺便说一句。 - xjcl
35
部署到生产环境时,出现了错误。 - Sahid rahutomo
11
我觉得这个解决方案对我没有用。但后来我注意到,在 --disable-web-security 后面没有加逗号。 - Pramod
显示剩余17条评论

107

自Flutter 3.3.0版本以来

实现了向flutter命令添加任何浏览器标志选项的功能。

flutter run -d chrome --web-browser-flag "--disable-web-security"

或者对于drive命令:

flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart -d web-server --web-browser-flag="--disable-web-security"

注意:这只用于开发测试。Flutter是在客户端的浏览器上显式执行的!你不应该也无法在生产环境中禁用它(正如@Tommy所述),因为它是浏览器的安全功能,不应该在Dart代码中更改。你需要在提供Flutter应用程序资源的Web服务器上启用CORS,以确保它适用于所有人。

如果你在服务端使用Dart语言而没有Flutter,还使用shelf,那么请查看此回答


我们如何在launch.json中使用这个标志? - aytunch
9
您可以在启动配置中添加args: {"name": ..., "request": "launch", "type": "dart", "args": ["--web-browser-flag=--disable-web-security"]} - User Rebo
在Android Studio中的运行配置中添加此标志是否可行? - Abdulaziz Alnahhas
1
当然可以@Abdulaziz:只需在运行配置的“附加运行参数”中添加标志即可:https://dev59.com/B1QI5IYBdhLWcg3w7QHJ#64686348 - User Rebo

24

我认为像建议的那样禁用Web安全性将使您暂时跳过当前错误,但当您进入生产环境或在其他设备上进行测试时,问题将继续存在,因为这只是一个变通方法。正确的解决方案是从服务器端允许来自请求域的CORS并允许需要的方法和凭据(如果需要)。


13
这是一项CORS(跨源资源共享)问题,您不需要删除/修改任何内容。您只需要从服务器端启用CORS请求即可正常工作。
在我的情况下,我已经使用node.js和express.js创建了一个服务器,因此我只需添加这个中间件函数,它将为每个请求运行。
app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Methods", "GET,PUT,PATCH,POST,DELETE");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

万岁!我收到了数据。

你只需要查看设置,启用服务器的CORS即可。


BOOOOM! 增添了一些东西! :) - undefined

9

使用 web-renderer 运行 / 编译您的 Flutter Web 项目。这应该可以解决本地和远程两个问题。

flutter run -d chrome --web-renderer html
flutter build web --web-renderer html

5
无法远程工作。 - scienticious
4
无法在本地或生产环境下工作。 - dingo
这个解决方案在Chrome中有效,但在其他浏览器中无法工作。 - TheTechGuy
1
在生产模式下,甚至在 Chrome 中也不会工作。只有当您的网站托管在 Firebase Hosting 上时,它才能正常运行。 - Thiago Silva
@ThiagoSilva 我认为你是正确的 - 我只在Firebase Hosting中测试过这个解决方案。 - Praharsh Bhatt

8
经过几个小时的测试,以下内容对我来说完美无缺。
将以下内容添加到PHP文件中:
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header("Access-Control-Allow-Headers: X-Requested-With");

这使得我在使用flutter时可以正确连接HTTP GET POST,没有任何问题。我在以下讨论中发现了这个问题:XMLHttpRequest error Flutter

这个对我有用。谢谢。 - Ariel Soriano Vassia
但我没有在我的Flutter网页中使用PHP。 - Noryn Basaya

6
禁用 Web 安全策略在开发中表现良好,但在生产环境中可能效果不佳。我在生产环境的做法是通过保持 Web 请求简单来完全避免预检 CORS 检查。对我而言,这意味着更改请求头以包含:
'Content-Type': 'text/plain'

尽管我实际上发送的是json,但将其设置为text/plain可以避免预检CORS检查。 我调用的Lambda函数不支持预检OPTIONS请求。
以下是其他方法的一些信息,可帮助保持请求简单并避免预检请求。

6

2023年3月更新

我正在使用Google Cloud Functions v2和Google Cloud Run来运行我的函数。我不再在Flutter客户端中调用CORS敏感的API或运行整个Node.js客户端应用程序,而是调用我用JavaScript编写的函数(在Google Cloud Functions v2 Node.js 18环境中运行)。这样,唯一需要调用Google Cloud Run的http.dart将是Flutter客户端的主进程,这将有助于解决原始问题。当然,使用Google Cloud Run会产生费用,但我相信这些费用对于运行我们的服务的整个功能来说是相当合理的[:


与Flutter Web一起使用大量外部API时,确实需要像Node.js或Django这样的服务器端引擎。实际上,由于CORS机制与端口号差异相关,当我们尝试使用内部API时,可能会出现相同的CORS错误。

有许多步骤和SO贡献者的答案建议使用Chrome扩展程序来避免CORS错误,但对于用户来说并不好。所有用户都应该下载浏览器扩展程序才能使用我们的单个网站,如果我们使用真正的服务器引擎,这种情况就不会存在。

据我所知,CORS是来自浏览器的,因此我们的Flutter iOS和Android应用程序使用相同的API代码时不会出现这些CORS错误。第一次在Flutter Web中遇到这个错误时,我相信我可以在我的应用程序代码行中处理CORS。但这对于用户和长期开发计划来说实际上并不健康。

希望所有Flutter Web新手都能理解Web对我们来说是一个相当复杂的领域。即使我在这里也是新手,我强烈建议所有从1.22.n稳定版开始的Flutter Web开发人员学习像Node.js这样的服务器端引擎。这是值得一试的。

如果您已经看到了我的自我答案,我在这里提供一个关于使用 Node.js 的 Flutter Web 的简单指南。Flutter Web 已经稳定,但是对于像我这样的新手来说,所有必要的基础设施都还没有完全准备好。因此,在您第一次进入 Web 领域时要小心,并希望您重新检查所有条件和要求,以确定您是否真正需要您的 Flutter 应用程序的 Web 版本,以及是否真的需要使用 Flutter 完成此工作。我的回答是肯定的,哈哈。

https://blog.logrocket.com/flutter-web-app-node-js/


1
当您将Firebase用作后端并仍然遇到错误时,我们该怎么办?! - SIMMORSAL
@SIMMORSAL 我不太确定你的Firebase相关错误是什么。我还没有将node js引擎和Firebase产品结合到那个程度。但如果你在某种情况下已经解决了这个错误,那么可以开启一个新的SO线程,标记为flutter-web、cors、firebase和firebase-<product-name>,如果你能在这里评论新线程的链接,我会非常感激。[:] - tsitixe
1
我已经找到问题的解决方案 https://stackoverflow.com/a/67830000/4457315 ... 不管怎样还是谢谢你。 - SIMMORSAL

6
如果您在运行Spring Boot服务器,则将"@CrossOrigin"添加到您的Controller或服务方法中。
@CrossOrigin
@PostMapping(path="/upload")
public @ResponseBody ResponseEntity<Void> upload(@RequestBody Object object) {
    // ...
}

我知道问题明确要求只使用“dart代码”的解决方案,但是我无法通过使用Dart代码来修复异常(例如通过更改标头)。


4

3
目前您的回答写得不清楚。请编辑并添加更多细节,以帮助其他人理解它如何回答所提出的问题。您可以在帮助中心中找到有关编写良好答案的更多信息。 - Community
在生产模式下,甚至在Chrome浏览器中也无法工作。它只能在您的网站托管在Firebase Hosting上时才能正常运行。 - Thiago Silva

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接