map_location_picker icon indicating copy to clipboard operation
map_location_picker copied to clipboard

Flutter Web AutocompletePlace XMLHttpRequest Error

Open Bylinkk opened this issue 2 years ago β€’ 17 comments

Hi,

After reading multiple XMLHttpRequest errors and CORS security issues, I can't work the autocomplete search on Chrome. Can we just remove this function to give the user the possibility to only use the current location button? Or can you help me to make this function work easily ? Thank you in advance for your return.

Bylinkk avatar May 09 '23 18:05 Bylinkk

Hi @Bylinkk I will update it as soon as possible. Could you please elaborate on your problem?

itsarvinddev avatar May 12 '23 23:05 itsarvinddev

Hey @Bylinkk , this is caused by CORS.

itsarvinddev avatar May 13 '23 04:05 itsarvinddev

Thanks for your feedback. Indeed the problem is caused by CORS. When I try to use a proxy, it doesn't work. I use the geoCodingBaseUrl parameter with this value : geoCodingBaseUrl: "https://api.allorigins.win/raw?url=https://maps.googleapis.com/maps/api/geocode/json/", I also tried this : geoCodingApiHeaders: const { "Access-Control-Allow-Origin":'*', "Access-Control-Allow-Methods": 'GET', }, concerning disabled security, it works well on my side but the user will not do it on his side !

I really don't know how to solve this problem!

Bylinkk avatar May 13 '23 19:05 Bylinkk

It seems to be only a problem with localhost, after the deployment CORS problems are automatically fixed. You can try it once πŸ€” I'm not sure.

itsarvinddev avatar May 13 '23 19:05 itsarvinddev

Hi,

I just did the test in production but the CORS problem is still present. You can check for yourself on the following links: Pre production web site Then click on "Menu | Commande WhatsApp" then on the profile icon of the bottom app bar then "Ajouter votre adresse de livraison".

The javascript console displays the CORS error:

/#/:1 Access to XMLHttpRequest at 'https://maps.googleapis.com/maps/api/geocode/json/geocode/json?latlng=0.0017568469044719824%2C-0.002709031105041504&key=API_KEY' from origin 'https://dev2.scan.feadys.com' 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.

Failed to load resource: net::ERR_FAILED

Google Maps JavaScript API has been loaded directly without a callback. This is not supported and can lead to race conditions and suboptimal performance. For supported loading patterns please see https://goo.gle/js-api-loading

Thank you for your help

Bylinkk avatar May 16 '23 14:05 Bylinkk

hi @rvndsngwn I am experiencing the same issue, tried already many things like adding the headers "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, POST, OPTIONS", "Access-Control-Allow-Headers": "X-Requested-With, Content-Type, Origin, Accept, token"

Also tried some CORS proxies, but those are just temporary solutions.

Still getting "has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.".

Tried to make server side changes, nothing helps. I don't know what to do anymore. My app works on mobile but not on web. Sadly

jansvanda avatar Jun 09 '23 15:06 jansvanda

https://pub.dev/packages/flutter_cors

Guys you can use this package only for local testing.

itsarvinddev avatar Jun 14 '23 20:06 itsarvinddev

https://community.flutterflow.io/c/community-tutorials/how-to-deal-with-those-cors-issues

itsarvinddev avatar Jun 14 '23 20:06 itsarvinddev

Hi @rvndsngwn I will test this. Thank you very much for your come back

Bylinkk avatar Jun 15 '23 05:06 Bylinkk

I have worked on it, the same issue was with me, so I used OpenStreetMap instead and got the desired result.

thisisprabhat avatar Sep 29 '23 02:09 thisisprabhat

This problem has been presented to me in several opportunities when I try to use google apis (youtube, address, places, etc) from flutter web, the way in which I have solved it is defining functions in my services api rest that make of pass buckets to make the requests to google and to return the answers to my application, in the case of the widget PlacesAutocomplete has the property placesBaseUrl, there you define your route in the backend where you consult the services of google, in my case it is: https://my.api.server.com/utils.

But the routes that I define in my server to consume the google services were:

https://my.api.server.com/utils/place/autocomplete/json?input=address exampl

for this service I use the function:

async getPlacesByInput(input: string): Promise { try { let response = await axios.get(https://maps.googleapis.com/maps/api/place/autocomplete/json?input=${input}&key=${GOOGLE_API_KEY}); if (response.status == 200) { return response.data; } } catch (error) { console.error('error', error); return {}; } }

https://my.api.server.com/utils/place/details/json?placeid=placeIdExample

and for this service I use the function:

async getPlaceDetails(placeId: string, returnAll: Boolean): Promise { try { let response = await axios.get(https://maps.googleapis.com/maps/api/place/details/json?place_id=${placeId}&key=${GOOGLE_API_KEY}); if (returnAll) { return response.data; } if (response.status == 200) { return { placeDetails: JSON.stringify(response.data.result), stateName: response.data.result.address_components.find((component: any) => component.types.includes('administrative_area_level_1'))?.long_name, }; } else { console.error(response.data); return ''; } } catch (error) { console.error('error', error); return ''; }

}

I hope my explanation helps you. Happy code!!!!

AndresPinto2203 avatar Jan 14 '24 10:01 AndresPinto2203

How to fix this CORS issue, Any update ?

AnandSaran avatar May 21 '24 16:05 AnandSaran

Any updates on this?? As for me it works fine on any pc's web browser but does not work from any mobile browser.

zahidshaikh08 avatar Aug 19 '24 11:08 zahidshaikh08

For Geocoding

You need to build a proxy on your server in order to be able to get your correct response. The actual service is always returning CORS issues so building your own make you control the access control.

On Flutter

GoogleMapLocationPicker(
              mapType: MapType.normal,
              geoCodingBaseUrl:
                  "Your REST (GET) API", // You need to add your API HERE
              geoCodingApiHeaders: {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
              },
              searchHintText: tr(LocaleKeys.choose_location),
              apiKey: firebase.app.options.apiKey,
              currentLatLng:
                  LatLng(currentPosition.latitude, currentPosition.longitude),
              onPlacesDetailsResponse: (pick) => onPlacePicked(pick!.result),
              onNext: (pick) => onPlacePicked(pick!),
              language: "fr",
              region: "ca",
            )

I built that quick NodeJS firebase function that mimic the same URL of geocoding (in that case) :

recalculateApi.get("/geocode/json?", async (req, res) => {  // Here make sure you use the exact "/geocode/json?" to make sure it fits the actual flutter call
  const latlng = req.query.latlng as string;
  const language = req.query.language as string;
  const key = req.query.key as string;

  if (!latlng || !language || !key) {
    res.status(400).send('Missing required query parameters: latlng, language, key');
    return;
  }

  try {
    const url = `https://maps.googleapis.com/maps/api/geocode/json?latlng=${latlng}&language=${language}&key=${key}`;
    console.log(`Calling ${url}`);
    const apiResponse = await axios.get(url);

    res.status(200).send(apiResponse.data);
  } catch (error: any) {
    res.status(500).send(`Error calling Google Maps API: ${error.message}`);
  }
});

Then it works fine. That still a lot of work for something that could already work....

bertrandgelinas avatar Sep 04 '24 05:09 bertrandgelinas

To resolve the CORS issue, easiest way is use Firebase function or Appwrite cloud function. Both are have freemium plans.

Thank you, @bertrandgelinas , for providing the best guidance on how to use firebase functions.

Firebase: https://firebase.google.com/docs/functions Appwrite: https://appwrite.io/docs/products/functions/functions

https://github.com/appwrite/templates/tree/main/dart

itsarvinddev avatar Sep 04 '24 10:09 itsarvinddev

The function of @bertrandgelinas concerns geocoding. For place search use this instead:

On flutter placesBaseUrl: "<REST API>/placesProxy", placesApiHeaders: const { 'Content-Type': 'application/json', 'Accept': 'application/json', },

On firebase function

`// Fonction Firebase pour proxy l'API Google Places
exports.placesProxy = functions.https.onRequest(async (req, res) => {
  // Ajouter l'en-tΓͺte CORS pour permettre l'accΓ¨s depuis n'importe quel domaine (localhost)
  res.set("Access-Control-Allow-Origin", "*");
  res.set("Access-Control-Allow-Methods", "GET, POST");
  res.set("Access-Control-Allow-Headers", "Content-Type, Authorization");

  // GΓ©rer les requΓͺtes OPTIONS pour CORS
  if (req.method === "OPTIONS") {
    res.status(204).send("");
    return;
  }

  const input = req.query.input;
  const language = req.query.language;
  const key = req.query.key;

  if (!input || !language || !key) {
    res.status(400).send("Missing required parameters: input, language, key");
    return;
  }

  try {
    // URL de l'API Google Places pour l'autocomplΓ©tion
    const url = `https://maps.googleapis.com/maps/api/place/autocomplete/json?input=${input}&language=${language}&key=${key}`;

    console.log(`Calling ${url}`);

    // Appel Γ  l'API Google Places via Axios
    const apiResponse = await axios.get(url);

    // RΓ©ponse avec les donnΓ©es de l'API
    res.status(200).send(apiResponse.data);
  } catch (error) {
    res.status(500).send(`Error calling Google Places API: ${error.message}`);
  }
});`

However, the search works well but there is an error when selecting the chosen address:

#0 packages/map_location_picker/src/autocomplete_view.dart 504:7 _getDetailsByPlaceId β”œβ”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„β”„ β”‚ β›” FormatException: SyntaxError: Unexpected token 'M', "Missing re"... is not valid JSON

I wrote my message too quickly

Bylinkk avatar Sep 21 '24 11:09 Bylinkk

@AndresPinto2203 Where do you call this function: getPlaceDetails ?

Bylinkk avatar Sep 21 '24 13:09 Bylinkk