Flutter Web CORS 错误终极解决方案
问题描述
在使用 Flutter Web 开发时,许多开发者会遇到 CORS (跨域资源共享) 错误,特别是在调用第三方 API 时。典型的错误信息如下:
Access to XMLHttpRequest at 'https://api.example.com' 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.
这个问题出现的原因是浏览器出于安全考虑,默认阻止跨域请求。虽然移动应用不受此限制,但 Web 应用必须遵守同源策略。
解决方案概览
解决 CORS 问题主要有三种方法:
- 服务端解决方案(推荐):在服务器端配置 CORS 头信息
- 开发环境解决方案:临时禁用浏览器安全策略用于开发测试
- 请求优化方案:调整请求方式避免触发预检请求
重要提示
生产环境中必须使用服务端解决方案,禁用浏览器安全策略仅适用于开发和测试环境。
服务端解决方案(推荐)
Node.js/Express 服务器
const express = require('express');
const cors = require('cors');
const app = express();
// 启用 CORS
app.use(cors());
// 或者自定义 CORS 配置
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();
});
PHP 服务器
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header("Access-Control-Allow-Headers: X-Requested-With");
// 处理 OPTIONS 预检请求
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
exit(0);
}
Spring Boot (Java)
@CrossOrigin
@PostMapping(path="/upload")
public @ResponseBody ResponseEntity<Void> upload(@RequestBody Object object) {
// 你的业务逻辑
}
Nginx 配置
location / {
# 处理 OPTIONS 预检请求
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept, Authorization';
add_header 'Access-Control-Max-Age' 1728000;
return 204;
}
# 添加 CORS 头
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Origin, Content-Type, Accept, Authorization';
}
开发环境解决方案
Flutter 3.3.0+ 版本
从 Flutter 3.3.0 开始,可以直接通过命令行参数禁用 Web 安全策略:
# 运行应用时禁用安全策略
flutter run -d chrome --web-browser-flag "--disable-web-security"
# 测试时禁用安全策略
flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart -d web-server --web-browser-flag="--disable-web-security"
使用 flutter_cors 包
安装并使用第三方工具简化流程:
# 安装 flutter_cors
dart pub global activate flutter_cors
# 禁用 CORS
fluttercors --disable
# 启用 CORS
fluttercors --enable
如果遇到 command not found
错误,需要将 pub 缓存目录添加到 PATH 环境变量:
# 对于 zsh 用户
echo 'export PATH="$PATH":"$HOME/.pub-cache/bin"' >> ~/.zshrc
source ~/.zshrc
# 对于 bash 用户
echo 'export PATH="$PATH":"$HOME/.pub-cache/bin"' >> ~/.bashrc
source ~/.bashrc
Android Studio 配置
在 Android Studio 中配置运行参数:
- 打开
Edit Configurations
- 在
Additional run args
中添加:--web-browser-flag "--disable-web-security"
请求优化方案
通过简化请求避免触发预检请求:
// 修改请求头,使用简单请求避免预检
var response = await http.post(
Uri.parse('https://api.example.com/endpoint'),
headers: {
'Content-Type': 'text/plain', // 使用简单内容类型
'Authorization': 'Bearer your_token',
},
body: jsonEncode(yourData),
);
简单请求的条件:
- 使用 GET、HEAD 或 POST 方法
- 仅包含安全的头部字段
- Content-Type 为以下之一:
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
常见错误排查
确保 URL 协议完整
dart// 错误:缺少 http:// 协议 baseUrl: "localhost:3000/" // 正确:包含完整协议 baseUrl: "http://localhost:3000/"
检查服务器是否正确处理 OPTIONS 请求 确保服务器对 OPTIONS 预检请求返回正确的 CORS 头信息
验证 CORS 包是否正确配置 如果使用 Express.js,确保
app.use(cors())
在路由定义之前调用
生产环境建议
生产环境警告
切勿在生产环境中使用禁用浏览器安全策略的方案。这会使你的应用和用户面临安全风险。
生产环境中应该:
- 明确指定允许的源,而不是使用通配符
*
- 配置合适的 Access-Control-Allow-Methods
- 根据需要设置 Access-Control-Allow-Headers
- 考虑使用凭证(如果需要携带 cookies 等凭证信息)
// 生产环境示例:限制特定源
app.use(cors({
origin: 'https://yourdomain.com',
methods: ['GET', 'POST'],
allowedHeaders: ['Content-Type', 'Authorization']
}));
总结
CORS 是浏览器实施的安全特性,无法通过纯 Dart 代码完全解决。最佳实践是:
- 开发环境:使用
--disable-web-security
标志或flutter_cors
工具 - 生产环境:在服务器端正确配置 CORS 头信息
- 优化请求:设计 API 请求以避免触发预检请求
通过合理配置服务器和优化请求策略,可以彻底解决 Flutter Web 中的 CORS 问题。