Flutter Web调用Google Maps API时的CORS问题解决方法
Flutter Web Google Maps地点自动补全CORS问题排查
问题背景
在Flutter Web中实现Google Maps地点自动补全功能,调用API地址为:https://maps.googleapis.com/maps/api/place/autocomplete/json?type=geocode&language=de&key=API_KEY&input=puratchi
功能在移动端运行正常,但Web端触发CORS错误。已在Google控制台移除所有API限制,同时配置了Nginx的CORS策略,但问题依旧。
现有实现代码
使用GetConnect的请求代码
Future<List<Prediction>> fetchingAutocomplete(String searchText) async { Uri autocompleteUri = Uri.parse( "https://maps.googleapis.com/maps/api/place/autocomplete/json?type=geocode&language=${kLanguageCode.value}&key=$kGoogleApiKey&input=$searchText"); Response response = await GetConnect().get("$autocompleteUri",headers: {"Content-Type": "application/json"}); if (response.statusCode == 200) { return AutocompleteModel.fromJson(response.body).predictions; } else { return AutocompleteModel.fromJson({}).predictions; } }
使用Dio的请求代码
Future<List<Prediction>> fetchingAutocomplete(String searchText) async { final client = dio.Dio(); // Add an interceptor to set headers before each request client.interceptors.add(dio.InterceptorsWrapper( onRequest: (dio.RequestOptions options, dio.RequestInterceptorHandler handler) { options.headers['Access-Control-Allow-Origin'] = 'https://angular.babelonia.nl'; options.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'; options.headers['Access-Control-Allow-Headers'] = 'Content-Type'; options.headers['Access-Control-Allow-Credentials'] = 'true'; handler.next(options); }, )); Uri autocompleteUri = Uri.parse( "https://maps.googleapis.com/maps/api/place/autocomplete/json?type=geocode&language=${kLanguageCode.value}&key=$kGoogleApiKey&input=$searchText"); dio.Response response = await client.get("$autocompleteUri", options: dio.Options(headers: {"Content-Type": "application/json"})); if (response.statusCode == 200) { return AutocompleteModel.fromJson(response.data).predictions; } else { return AutocompleteModel.fromJson({}).predictions; } }
Nginx CORS配置
location / { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE'; add_header 'Access-Control-Allow-Headers' 'Content-Type'; add_header 'Access-Control-Allow-Credentials' 'true'; }
报错信息
Access to XMLHttpRequest at 'https://maps.googleapis.com/maps/api/place/autocomplete/json?type=geocode&language=en&key=API_KEY&input=c' from origin 'https://angular.babelonia.nl' 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.
问题分析与解决方案
核心错误点
- 请求头设置错误:你在Dio拦截器中添加的
Access-Control-*系列头是响应头,不属于请求头范畴。这些头应该由目标服务器(Google Maps API)返回,前端请求携带这些头不仅无效,还可能触发额外预检请求。 - Nginx配置未生效:当前请求是前端直接发送到
maps.googleapis.com,完全绕开了你的Nginx服务器,所以Nginx的CORS配置对这个请求没有任何作用。
正确解决方案
方案1:使用Google Maps JavaScript SDK(推荐)
Google官方推荐Web环境下使用JavaScript SDK实现地点自动补全,该SDK通过加载脚本的方式调用,不受浏览器CORS限制,是最适配Web场景的方案。
方案2:搭建后端代理服务器
在你的Nginx服务器上配置反向代理,让前端请求先发送到自己的服务器,再由服务器转发到Google Maps API,这样Nginx的CORS配置就能生效:
- 修改Nginx配置,添加代理规则:
location /google-places-autocomplete { add_header 'Access-Control-Allow-Origin' 'https://angular.babelonia.nl'; add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'Content-Type'; add_header 'Access-Control-Allow-Credentials' 'true'; # 处理OPTIONS预检请求 if ($request_method = OPTIONS) { return 204; } # 转发请求到Google Maps API proxy_pass https://maps.googleapis.com/maps/api/place/autocomplete/json; proxy_set_header Host maps.googleapis.com; proxy_set_header X-Real-IP $remote_addr; }
- 修改Flutter Web中的请求地址,指向代理接口:
Uri autocompleteUri = Uri.parse( "https://your-domain.com/google-places-autocomplete?type=geocode&language=${kLanguageCode.value}&key=$kGoogleApiKey&input=$searchText");
方案3:检查Google API控制台配置
确认以下两点:
- 已启用Places API(仅移除限制不够,需确保API本身已开启)
- API密钥的应用限制中,可尝试添加
https://angular.babelonia.nl作为允许的HTTP引用,避免潜在权限问题
额外优化建议
- 移除Dio拦截器中所有
Access-Control-*的请求头设置 - GetConnect请求中,GET请求无需设置
Content-Type: application/json,可移除该头以减少预检请求触发概率
内容的提问来源于stack exchange,提问作者Senthur Kumaran
相关产品推荐
相关产品推荐

