使用 Google Places API(firebase 托管)的 Flutter-Web 出现 XMLHttpRequest 错误

Fer*_*jab 7 cors google-places-api firebase-hosting flutter-web

在我的 Flutter-Web 应用程序中,我试图使用 flutter_google_places 包获取地址。我正在尝试使用简单的代码来获取自动完成地址字段(MyTextField 只是一个自定义的文本字段):

final addressField = MyTextField(
  controller: _addressController,
  labelText: 'Indirizzo',
  readOnly: true,
  onTap: () async {
    await PlacesAutocomplete.show(
      context: context,
      apiKey: kGoogleApiKey,
      mode: Mode.overlay,
      onError: (error){print('ERROR: $error');},
    );
  },
);
Run Code Online (Sandbox Code Playgroud)

当我运行应用程序并向该字段插入一些内容时,我没有得到任何结果。但是我收到此错误(从主机上的检查控制台捕获,并且我在本地也收到相同的错误):

Access to XMLHttpRequest at 'https://maps.googleapis.com/maps/api/place/autocomplete/json?input=h&key=**MY-API-KEY**' from origin 'https://**MY-HOSTING**.firebaseapp.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Run Code Online (Sandbox Code Playgroud)

我读到这是一个服务器端问题,我尝试像这样修改 firebase.json:

{
  "hosting": {
    "public": "build/web",
    "ignore": [
      "firebase.json",
      "**/.*",
      "**/node_modules/**"
    ],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ],
    "headers": [ {
      "source" : "**",
      "headers" : [ {
        "key" : "Access-Control-Allow-Origin",
        "value" : "*"
      } ]
    }]
  }
}

Run Code Online (Sandbox Code Playgroud)

部署了,但也得到了同样的错误。

任何有关解决(本地和托管)的提示表示赞赏。

Fer*_*jab 5

因此,由于没有答案,我正在分享解决我的情况的方法,希望很快能从专家那里得到更好的答案。

问题:

Google 放置 API 来阻止CORS。所以我们无法从客户端发出请求。当 PlacesAutocomplete 小部件向 Google 地点 API 发出 http 请求时,如下所示:

https://maps.googleapis.com/maps/api/place/autocomplete/json?input={queryString}&key={API-Key}
Run Code Online (Sandbox Code Playgroud)

此客户端请求将被阻止。

我的解决方案:

首先,我不再使用 PlacesAutocomplete 小部件。

我编写了一个简单的云函数,它以 Url 作为参数,然后对同一 Url 发出 http 请求并返回数据。但这次请求将来自服务器端,因此我可以绕过 cors。所以在index.ts内部我编写了以下函数:

const functions = require('firebase-functions');
const axios = require('axios');

exports.getDataFromUrl = functions.https.onCall(async (data, context) => {
  const url = data.url;
  try {
    const info = await axios.get(url);
    return info.data;
  } catch (error) {
    return (error);
  }
});
Run Code Online (Sandbox Code Playgroud)

然后,我从客户端编写了这个函数(在 dart 中),它为任何 url 调用云函数:

  Future httpRequestViaServer({url}) async {
    HttpsCallable callable = CloudFunctions.instance.getHttpsCallable(
      functionName: 'getDataFromUrl',
    );
    try {
      final HttpsCallableResult result = await callable.call(
        <String, dynamic>{
          'url': url,
        },
      );
      return (result.data);
    } on CloudFunctionsException catch (e) {
        print('caught firebase functions exception');
        print(e.code);
        print(e.message);
        print(e.details);
        return null;
    } catch (e) {
        print('caught generic exception');
        print(e);
        return null;
    }
Run Code Online (Sandbox Code Playgroud)

现在我可以调用此函数从项目中的任何位置获取 API url(或任何 url)的数据。

我结束了构建自己的 autoComplete 小部件,它使用此函数调用 API。

希望这个答案对遇到类似问题的人有所帮助,并期待专家更好的答案。


小智 0

如果您想在本地测试此功能,可以使用 Chrome 的“允许 CORS:Access-Control-Allow-Origin”来禁用它