Flutter Web 跨域(CORS)问题(chatgpt总结)

1. 什么是 Web 跨域?

在 Web 中,浏览器存在一套安全机制:

同源策略(Same-Origin Policy)

它规定:一个网页默认不能随意读取另一个不同 Origin 的资源。

一个 Origin 由三个部分组成:

TEXT已复制
协议 + 域名 + 端口

例如:

TEXT已复制
http://localhost:8080
│      │          │
协议   域名       端口

以下情况都属于不同 Origin:

TEXT已复制
http://example.com
https://example.com

协议不同。

TEXT已复制
https://example.com
https://api.example.com

域名不同。

TEXT已复制
https://example.com:8080
https://example.com:9000

端口不同。


2. 为什么浏览器要限制跨域?

主要是为了安全。

例如用户已经登录了:

TEXT已复制
https://bank.com

浏览器中可能保存着银行网站的 Cookie。

如果任何网站都可以随便读取银行的数据,那么恶意网站:

TEXT已复制
https://evil.com

就可能尝试读取:

TEXT已复制
https://bank.com/account

所以浏览器默认限制:

TEXT已复制
evil.com
   │
   └──────→ bank.com
              ❌

这就是同源策略。


3. 什么是 CORS?

CORS:

Cross-Origin Resource Sharing
跨源资源共享

它是浏览器提供的一种机制,让服务器可以明确告诉浏览器:

“我允许某个 Origin 的网页访问我的资源。”

例如 Flutter Web:

TEXT已复制
http://localhost:8080

请求:

TEXT已复制
https://api.example.com/user

服务器可以返回:

HTTP已复制
Access-Control-Allow-Origin: http://localhost:8080

浏览器看到以后,就允许网页读取响应。


4. Flutter Web 为什么会遇到 CORS?

Flutter 本身不是 CORS 的核心问题。

关键在于:

Flutter Web 最终运行在浏览器中。

例如使用 Dio:

DART已复制
final dio = Dio();

final response = await dio.get(
  'https://api.example.com/user',
);

在 Android 中:

TEXT已复制
Flutter
   ↓
Dio
   ↓
网络
   ↓
API

一般不会受到浏览器 CORS 的限制。

但是 Flutter Web:

TEXT已复制
Flutter
   ↓
Dio
   ↓
浏览器 Chrome
   ↓
API

Chrome 会执行浏览器的同源策略和 CORS 检查。

所以:

TEXT已复制
Flutter Web + Dio
        ↓
      Chrome
        ↓
      CORS检查
        ↓
   ┌────┴────┐
   ↓         ↓
允许        不允许
   ↓         ↓
  ✅        ❌

5. Dio 会不会出现跨域问题?

会。

Dio 本身不能绕过浏览器 CORS。

例如:

DART已复制
final response = await dio.get(
  'https://api.example.com/test',
);

如果 API 没有正确配置 CORS:

Chrome Console 可能出现:

TEXT已复制
Access to XMLHttpRequest at
'https://api.example.com/test'
from origin
'http://localhost:xxxxx'
has been blocked by CORS policy

Dio 可能表现为:

TEXT已复制
DioExceptionType.connectionError

或者:

TEXT已复制
XMLHttpRequest error.

所以:

Dio 能发请求 ≠ 浏览器一定允许读取这个请求的结果。


6. 如何判断是不是 CORS?

首先打开:

TEXT已复制
F12
→ Console

如果看到:

TEXT已复制
blocked by CORS policy

基本就可以确定是 CORS 问题。

典型错误:

TEXT已复制
Access to XMLHttpRequest at 'https://xxx.com/api'
from origin 'http://localhost:xxxxx'
has been blocked by CORS policy

而 Dio 代码中可能只看到:

TEXT已复制
DioException [connection error]
XMLHttpRequest error

因此:

判断 Flutter Web CORS 问题时,Chrome Console 比 Dio 的异常信息更重要。


7. 为什么有些 API 可以正常访问?

因为服务器已经配置了 CORS。

例如:

HTTP已复制
Access-Control-Allow-Origin: *

表示允许跨 Origin 访问。

所以:

TEXT已复制
Flutter Web
    ↓
Dio
    ↓
API
    ↓
Access-Control-Allow-Origin: *
    ↓
Chrome
    ↓
✅ 200

例如测试:

DART已复制
final response = await dio.get(
  'https://jsonplaceholder.typicode.com/posts/1',
);

如果得到:

TEXT已复制
200

并不代表 Flutter Web 没有 CORS。

只是说明:

这个 API 允许当前请求跨域访问。


8. Postman 为什么可以请求,而浏览器不行?

这是一个很常见的误区。

例如:

TEXT已复制
Flutter Web → API

出现:

TEXT已复制
❌ CORS

但是:

TEXT已复制
Postman → API

得到:

TEXT已复制
✅ 200

这并不矛盾。

因为:

TEXT已复制
Postman
   ↓
API

不是网页浏览器环境。

而:

TEXT已复制
Flutter Web
   ↓
Chrome
   ↓
API

需要遵守浏览器的同源策略。

所以:

Postman 能请求 ≠ 浏览器能请求。


9. 临时解决方法:关闭 Chrome Web Security

开发 Flutter Web 时,可以使用:

TEXT已复制
--disable-web-security

让 Chrome 关闭 Web Security,从而绕过浏览器的 CORS 检查。

一种修改 Flutter SDK 的方法:

① 修改 chrome.dart

找到:

TEXT已复制
flutter/packages/flutter_tools/lib/src/web/chrome.dart

在 Chrome 启动参数的位置添加:

DART已复制
'--disable-web-security',

② 删除 Flutter 缓存

删除:

TEXT已复制
flutter/bin/cache/flutter_tools.snapshot
flutter/bin/cache/flutter_tools.stamp

③ 重新生成 Flutter Tools

执行:

BASH已复制
flutter doctor -v

然后重新运行:

BASH已复制
flutter run -d chrome

这样 Flutter 启动 Chrome 时,就会带上:

TEXT已复制
--disable-web-security

从而可以用于测试一些没有正确配置 CORS 的 API。


10. ⚠️ –disable-web-security 的注意事项

这个方法本质上是在告诉 Chrome:

关闭浏览器的 Web 安全限制。

因此它适合:

TEXT已复制
开发环境
测试
临时调试 CORS

不适合:

TEXT已复制
生产环境
正式部署的网站

因为这不是在真正解决 CORS。

正确的生产环境解决方案应该是:

TEXT已复制
Flutter Web
     ↓
     API
     ↓
服务器配置 CORS
     ↓
Access-Control-Allow-Origin
     ↓
Chrome
     ↓
✅

而不是:

TEXT已复制
Flutter Web
     ↓
关闭 Chrome 安全策略
     ↓
API
     ↓
✅

11. 正规解决方案

如果 Flutter Web:

TEXT已复制
http://localhost:8080

访问:

TEXT已复制
https://api.example.com

那么后端应该允许:

HTTP已复制
Access-Control-Allow-Origin: http://localhost:8080

生产环境则应该根据实际域名配置,例如:

HTTP已复制
Access-Control-Allow-Origin: https://example.com

也可以根据后端框架配置 CORS。


12. VPN 和 CORS 没有直接关系

VPN:

改变网络连接方式、路由、出口 IP 等。

CORS:

浏览器控制网页是否可以读取其他 Origin 的资源。

所以:

TEXT已复制
VPN 开启
+
API 没有 CORS
=
❌ 仍然可能 CORS

而:

TEXT已复制
VPN 关闭
+
API 正确配置 CORS
=
✅ 正常访问

因此:

VPN 不会自动解决 CORS。


13. Flutter Web + Dio 的完整关系

可以记住这个流程:

TEXT已复制
       Flutter Web
           │
           ▼
          Dio
           │
           ▼
        Chrome
           │
    同源策略 / CORS
           │
   ┌───────┴───────┐
   │               │
服务器允许       服务器不允许
   │               │
   ▼               ▼
  ✅              ❌
 200          CORS Error

14. 最重要的几个结论

① CORS 主要是浏览器的问题

不是 Dio 独有的问题,也不是 Flutter 独有的问题。


② Flutter Web 才特别容易遇到

因为 Flutter Web 运行在浏览器中。


③ Dio 不能绕过 CORS

Dio 只是 HTTP 客户端。


④ API 是否允许跨域由服务器配置

常见响应头:

HTTP已复制
Access-Control-Allow-Origin

⑤ Postman 能请求不代表浏览器能请求

因为 Postman 不受浏览器同源策略限制。


⑥ VPN 和 CORS 没有直接关系

VPN 不会自动解决跨域。


⑦ --disable-web-security 可以临时测试

Flutter 可以修改:

TEXT已复制
flutter/packages/flutter_tools/lib/src/web/chrome.dart

添加:

DART已复制
'--disable-web-security',

然后删除:

TEXT已复制
flutter/bin/cache/flutter_tools.snapshot
flutter/bin/cache/flutter_tools.stamp

执行:

BASH已复制
flutter doctor -v

再:

BASH已复制
flutter run -d chrome

但这只是开发调试方案。


一句话记忆

Flutter Web 使用 Dio 请求 API 时,Dio 负责发请求,Chrome 负责执行浏览器安全策略,服务器通过 CORS Header 告诉 Chrome“哪些网页可以读取我的响应”。

所以遇到:

TEXT已复制
blocked by CORS policy

第一反应应该是:

TEXT已复制
F12 → Console
        ↓
确认 CORS
        ↓
检查服务器 CORS 配置

而不是首先修改 Flutter。