简体   繁体   English

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

[英]XMLHttpRequest error with Flutter-Web using Google Places API (firebase hosting)

Inside my Flutter-Web application I'm trying to get address using flutter_google_places package. I'm trying simple code to get autocomplete address field (MyTextField is just a customized Text Field):在我的 Flutter-Web 应用程序中,我正在尝试使用 flutter_google_places package 获取地址。我正在尝试使用简单的代码来获取自动完成地址字段(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');},
    );
  },
);

When I run the app and insert something to the field I don't get any result.当我运行应用程序并向字段中插入内容时,我没有得到任何结果。 But I get this error (captured from inspect console on hosting, and I get the same error locally also):但是我收到此错误(从托管检查控制台捕获,我也在本地收到相同的错误):

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.

I read that it's a server-side issue and I tried to modify firebase.json like this:我读到这是一个服务器端问题,我试图像这样修改 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" : "*"
      } ]
    }]
  }
}

Deployed that but also got the same error.部署了它,但也遇到了同样的错误。

Any tips about solving that (locally and on hosting) are appreciated.任何有关解决该问题(本地和托管)的提示都将受到赞赏。

So as there was no answers I'm sharing what solved my situation, hope getting better answers from experts soon.因此,由于没有答案,我正在分享解决我的情况的方法,希望尽快从专家那里得到更好的答案。

The Problem:问题:

Google places API prevents CORS .谷歌放置 API 防止CORS So we can't make a request from client-side.所以我们不能从客户端发出请求。 And As the PlacesAutocomplete widget makes http request to the Google places API like this:并且由于 PlacesAutocomplete 小部件向 Google 发出 http 请求,因此 API 如下所示:

https://maps.googleapis.com/maps/api/place/autocomplete/json?input={queryString}&key={API-Key}

This client-side request will be prevented.此客户端请求将被阻止。

My Solution:我的解决方案:

First I'm not using PlacesAutocomplete widget anymore.首先,我不再使用 PlacesAutocomplete 小部件。

I wrote a simple cloud function that takes Url as parameter then makes http request for the same Url and returns data.我写了一个简单的云 function ,它以 Url 作为参数,然后对相同的 Z02A3A3A357710FB59ZDFB12 数据发出 http 请求并返回。 But this time the request will be from server-side so I can bypass cors.但是这次请求将来自服务器端,所以我可以绕过 cors。 So Inside index.ts I wrote the following function:所以在index.ts里面我写了以下 function:

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);
  }
});

Then from client-side I wrote this function (in dart) which calls the cloud function for any url:然后从客户端我写了这个 function(在飞镖中),它为任何 url 调用云 function:

  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;
    }

Now I can call this function to get data for the API url (or any url) from anywhere in my project.现在我可以调用这个 function 从我项目中的任何位置获取 API url(或任何 url)的数据。

I ended building my own autoComplete widget which calls the API using this function.我结束了构建自己的 autoComplete 小部件,该小部件使用此 function 调用 API。

Hope this answer helps someone facing similar problem, and looking forward for better answers from experts.希望这个答案对面临类似问题的人有所帮助,并期待专家提供更好的答案。

I found a solution that lets you keep using PlacesAutocomplete in this github comment: https://github.com/lejard-h/google_maps_webservice/issues/70#issuecomment-636919093我找到了一个解决方案,可以让您在此 github 评论中继续使用 PlacesAutocomplete: https://github.com/lejard-h/google_maps_webservice/issues/70#issuecomment-636919093

GoogleMapsPlaces(
  apiKey: 'YOUR_API_KEY',
  baseUrl: kIsWeb
      ? 'https://cors-anywhere.herokuapp.com/https://maps.googleapis.com/maps/api'
      : null,
);

This other StackOverflow answer talks about how the solution works a little more, as well as give more info about cors-anywhere (including how to host your own): https://stackoverflow.com/a/43881141/3001277这个 StackOverflow 的另一个答案讨论了该解决方案的工作原理,并提供了有关 cors-anywhere 的更多信息(包括如何托管您自己的): https://stackoverflow.com/a/43881141/3001277

if you want to test this locally you can use the "Allow CORS: Access-Control-Allow-Origin" for Chrome to disable it如果您想在本地进行测试,您可以使用 Chrome 的“Allow CORS: Access-Control-Allow-Origin”来禁用它

Based on this answer ,基于这个答案

Use https://app.cors.bridged.cc/ instead of https://cors-anywhere.herokuapp.com/使用https://app.cors.bridged.cc/代替https://cors-anywhere.herokuapp.com/

Follow this article for more details: https://blog.grida.co/cors-anywhere-for-everyone-free-reliable-cors-proxy-service-73507192714e关注这篇文章了解更多详情: https://blog.grida.co/cors-anywhere-for-everyone-free-reliable-cors-proxy-service-73507192714e

This API is not meant for the web.此 API 不适用于 web。 To take advantage of Place Autocomplete on Flutter web, it is necessary to use a library that implements the interop with javascript like this: https://pub.dev/packages/flutter_google_places_sdk To take advantage of Place Autocomplete on Flutter web, it is necessary to use a library that implements the interop with javascript like this: https://pub.dev/packages/flutter_google_places_sdk

I Reference to the answer of Feras Senjab:我参考了 Feras Senjab 的回答:

The MEthods should have slightly changed by now in order to still work.为了仍然有效,方法现在应该稍微改变了。

For the index.js no changes对于 index.js 没有变化

// Forwards a request call to get Google Places AUtocomplete Running
exports.getGooglePlacesAutocomplete = functions.https.onCall(async (data, context) => {
  const url = data.url;
  try {
    console.log(url);
    const info = await axios.get(url);
    console.log(info);
    return info.data;
  } catch (error) {
    return (error);
  }
});

For the CLient side, this is the update对于客户端,这是更新

import 'package:cloud_functions/cloud_functions.dart';

Future googlePlacesAutocompleteRequestViaServer({url}) async {
  HttpsCallable callable =
      FirebaseFunctions.instance.httpsCallable('getGooglePlacesAutocomplete');
  try {
    final HttpsCallableResult result = await callable.call(
      <String, dynamic>{
        'url': url,
      },
    );
    return (result.data);
  } on FirebaseFunctionsException 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;
  }
}

Call Google Places API from Flutter Web.从 Flutter Web 拨打 Google Places API。

Add Headers as below, to your api-client.将标题如下添加到您的 api-client。

{
 "x-requested-with" : "XMLHttpRequest"
}

Now, append your Google Places API with现在,append 您的 Google Places API 与

https://proxy.cors.sh

Thus, call your API as因此,将您的 API 称为

https://proxy.cors.sh/<Google Places API>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 XMLHttpRequest 错误 flutter web [启用 CORS AWS API 网关] - XMLHttpRequest error in flutter web [Enabling CORS AWS API gateway] 如何使用 Firebase 为 Flutter Web 加载特定的 url 页面 - How can I load a specific url page using Firebase Hosting for Flutter Web Troubleshooting Dart XMLHttpRequest error - works for Flutter mobile, not for Flutter web - Troubleshooting Dart XMLHttpRequest error - works for Flutter mobile, not for Flutter web Firebase 托管 Flutter Web App 未清除首次部署的缓存 - Firebase Hosting Flutter Web App not clearing Cache of first deploy Flutter web 应用程序丢失 firebase.json 并在部署到 firebase 托管时显示“欢迎 Firebase 托管设置完成” - Flutter web app is missing firebase.json and shows "Welcome Firebase Hosting Setup Complete" when deployed to firebase hosting Flutter web - Firebase 云消息 - 在本地主机上运行正常,而不是当我上传到 firebase 托管 - Flutter web - Firebase cloud messaging - running OK on localhost, not when I upload to firebase hosting 如何使用 Firebase 主机在 Flutter 中设置 404 未找到页面 - how to setup 404 Not found page in Flutter using Firebase Hosting 使用 Firebase Cloud Functions 中的 API 和受限 API 密钥 - Using places API from Firebase Cloud Functions with restricted API Key Flutter web 应用程序在部署到 firebase 主机后返回空白页 - Flutter web app is returning blank page after being deployed to firebase hosting Flutter 错误:(getGoogleApiForMethod() 返回 Gms:com.google.firebase.auth.api.internal.zzaq@3e2567) - Flutter Error:(getGoogleApiForMethod() returned Gms: com.google.firebase.auth.api.internal.zzaq@3e2567)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM