6

Problem

I have a Flutter Web project hosted on Firebase Hosting rendered with CanvasKit and I can't make it load external images hosted in a Xano CDN or load GooglePlaces API results (autocompiling). I read many other solutions (like this or this or this) but none works. I also configured CORS on Google Cloud.

My files

This is my firebase.json file:

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

In index.html I have appended the following script, right before the </body> tag:

<!-- Firebase -->
<script type="module">
  // Import the functions you need from the SDKs you need
  import { initializeApp } from "https://www.gstatic.com/firebasejs/9.6.10/firebase-app.js";
  import { getAnalytics } from "https://www.gstatic.com/firebasejs/9.6.10/firebase-analytics.js";
  // TODO: Add SDKs for Firebase products that you want to use
  // https://firebase.google.com/docs/web/setup#available-libraries

  // Your web app's Firebase configuration
  // For Firebase JS SDK v7.20.0 and later, measurementId is optional
  const firebaseConfig = {
    apiKey: *mykey*,
    authDomain: "hearth-148b0.firebaseapp.com",
    projectId: "hearth-148b0",
    storageBucket: "hearth-148b0.appspot.com",
    messagingSenderId: *id*,
    appId: *myappid*,
    measurementId: *id*
  };

  // Initialize Firebase
  const app = initializeApp(firebaseConfig);
  const analytics = getAnalytics(app);
</script>

I tried to include the header in the CachedNetworkImage:

return CachedNetworkImage(
    httpHeaders: {"Access-Control-Allow-Origin": "*"},
    imageUrl: imageUrl,
    fit: fit,
    width: width,
    height: height,
    progressIndicatorBuilder: (context, url, downloadProgress) =>
        LoadingPlaceholder(width: width),
    errorWidget: (context, url, error) => SizedBox(width: width),
  );

And I tried to include the headers in GooglePlace initializer:

 final GooglePlace googlePlace = GooglePlace(
    kTokenGMaps,
    headers: {"Access-Control-Allow-Origin": "*"},
  );

The errors

These are the type of errors I get from the browser console:

Failed to load resource: net::ERR_BLOCKED_BY_CLIENT

or

Access to XMLHttpRequest at 'https://storage.googleapis.com/xatr-ly1x-gkt1.n7.xano.io/vault/xhL5_hu1/fMPW0YCx/C01_Ng../9de15d31/Monumento_ai_caduti_in_Corso_Europa.jpg' (redirected from 'https://xatr-ly1x-gkt1.n7.xano.io/vault/xhL5_hu1/fMPW0YCx/C01_Ng../Monumento_ai_caduti_in_Corso_Europa.jpg?tpl=big:box') from origin 'https://hearth-148b0.web.app' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Deploy

These are the commands I use to deploy on firebase, from android studio:

flutter build web
firebase deploy

Alternative

I also tried to use another host with FTP and setting the .htaccess file to:

Header set Access-Control-Allow-Origin *

but no success.

3

1 Answer 1

3

I resolved this problem by adjusting the CORS settings on the server side. Initially, I thought it was a client problem, but it turned out to be caused by a misconfiguration on the server.

In my case, I was using Firebase Storage, and I had to create a cors.json file on my computer to enable CORS. Here's what my configuration looked like:

[
  {
    "origin": ["*"],
    "method": ["GET"],
    "maxAgeSeconds": 3600
  }
]

To break this down:

  • "origin": ["*"] allows requests from any origin to access the resource. You can specify a specific domain or a list of domains to restrict the origins that are allowed to access the resource.

  • "method": ["GET"] allows only GET requests to access the resource. You can include other HTTP methods like POST, PUT, DELETE, etc. to restrict the methods that are allowed to access the resource.

  • "maxAgeSeconds": 3600 caches the CORS configuration in the browser for 1 hour (3600 seconds). Subsequent requests from the same origin and method will not require a CORS check during the cache duration.

After creating the cors.json file, and after installing gsutil, execute this command in your terminal:

gsutil cors set cors.json gs://<bucket>.appspot.com

Make sure to replace <bucket> with the name of your storage bucket.

By following these steps, I was able to fix my CORS issue and enable access to my resources.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.