Flutter web can't load network image from another domain
Asked Answered
H

17

104

I can't load network images in flutter web from other domains with API calls. getting this error

Trying to load an image from another domain? Find answers at: https://flutter.dev/docs/development/platform-integration/web-images ImageCodecException: Failed to load network image.

any help?

Handmedown answered 10/1, 2021 at 13:29 Comment(4)
Try to read the documentation here: flutter.dev/docs/development/platform-integration/…Mandrel
I tried but I was not able to follow throughHandmedown
Can you show me your code where you used network images ?Leroi
try using this package "image_network 2.5.1" this will work fine on every platformKetosis
R
136

For being able to display your images from any other domain or from Firebase Storage on a Flutter web page, you have to configure your data for CORS:

  1. Open the GCP console, select your project and start a cloud terminal session by clicking the >_ icon button in the top navbar.

  2. Click the open editor button (pencil icon), then create the cors.json file. The cors.json file should look like this:

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

    I set the origin to * which means that every website can display your images. But you can also insert the domain of your website there to restrict access.

  3. Run gsutil cors set cors.json gs://your-bucket


If you need more information: https://cloud.google.com/storage/docs/configuring-cors

Rosin answered 8/2, 2021 at 15:30 Comment(11)
On Step 2, in order to create the cors.json file, click on the 3 dots (...) on the same row as Explorer:XXXX OR just click on File>new file. Step 3: You'll find "your-bucket" in your firebase STORAGE console and YOU WILL HAVE TO AUTHORIZE when you run the shell command.Skinned
To verify: gsutil cors get gs://your-bucketPastille
Still not working after the all above suggestions, Trying to display YouTube thumbnails in my flutter web app. Am I missing something after point 3. Is there any reload or refresh command need to perform. Please suggest me.Hydrazine
This looks like configuration only related to firebase and google cloud. Is there any additional configuration involved in flutter app as well? As images are still not loading and throws missing CORS headers error.Lactescent
Okay, so it's working for me, I was running in localhost and also using origin as "https://firebasestorage.googleapis.com/v0/b/my_app_name.appspot.com", which on changing to "*" starts working. But how to correctly use cutom origin instead of "*"?Lactescent
@sh_ark use https://my_app_name.we.app this is the domain the request is coming fromWreck
for people like me who don't know anything about buckets and get 403 errors, you get your bucket List with gsutil ls, and check which one is used for your app and set cors.json for that one.Bertine
what is maxageseconds in this codeFruma
I needed to use the next command in order to make it work: gsutil cors set cors.json gs://your-bucketRenter
#71193848 all step by step is hereKumasi
AccessDeniedException: 403 [email protected] does not have storage.buckets.update access to the Google Cloud Storage bucket. Permission 'storage.buckets.update' denied on resource (or it may not exist).Brittnybritton
P
98

There are two ways to resolve this either run your app using HTML renderer or set up the CORS configuration.

1. Using HTML renderer

Taken from the docs

CORS is a mechanism that browsers use to control how one site accesses the resources of another site. It is designed such that, by default, one web-site is not allowed to make HTTP requests to another site using XHR or fetch. This prevents scripts on another site from acting on behalf of the user and from gaining access to another site’s resources without permission

When using <img>, <picture>, or <canvas>, the browser automatically blocks access to pixels when it knows that an image is coming from another site and the CORS policy disallows access to data.

Flutter has two renderers for web, canvaskit and html When you run/build app on the flutter web it uses renderers based on the device where its running.

HTML renderer: when the app is running in a mobile browser.

CanvasKit renderer: when the app is running in a desktop browser.

auto (default) - automatically chooses which renderer to use.

The HTML renderer can load cross-origin images without extra configuration. so you could use these commands to run and build the app.

flutter run -d chrome --web-renderer html // to run the app

flutter build web --web-renderer html --release // to generate a production build

source: https://docs.flutter.dev/development/tools/web-renderers

2. Setup CORS Configuration

  • Download the Google-cloud-sdk which contains a tool called gsutil
  • In your flutter project create a file called cors.json and add this json content, which will remove all domain restrictions. (It doesn't matter where this file is located)
[
  {
    "origin": ["*"],
    "method": ["GET"],
    "maxAgeSeconds": 3600
  }
]
  • Run gcloud init (located in google-cloud-sdk/bin)
  • Authenticate yourself by clicking the link and choose the project in the console.
  • finally execute gsutil cors set cors.json gs://<your-bucket-name>.appspot.com You can find your bucket name in firebase storage.

I have documented this entire process in github gists

Plumley answered 13/3, 2021 at 19:4 Comment(10)
where in your file tree do you place the cors.json file? (does it matter?)Ruelle
cors.json doesn't really matter once you run the gsutil command.Plumley
@MaheshJamdade cors.json file is actually required for gsutil to read our cors configuration.Also Cors.json file should be placed in path where you'll run G-Cloud commandFacet
@InderPalSingh we no longer need the cors.json file once we upload the configuration by running the last command.Plumley
I too recommend the 2nd solution... but what happens when we cant set this on a domain/server that doesnt give us permission to do so? How do we handle CORS then?Chary
Thanks. I get an error on the last step (for solution 2): CommandException: "cors" command spanning providers not allowed. - any idea how to fix?Graphic
@kdon do you have a cors.json file created?Plumley
@MaheshJamdade yes had the file but realized I needed to run in the command from the project directory. Working now, thanks.Graphic
@MaheshJamdade how long it takes after gsutil cors set command until the cors issue gone? tried to set the cors few minutes ago but it seems nothings changesRafflesia
checked the cors using gsutil cors get gs://your-bucket and the json file was there but still got a cors error while loading the imageRafflesia
H
55

I solved this issue by using html renderer:

flutter build web --release --web-renderer html

or

flutter run --web-renderer html
Handmedown answered 13/1, 2021 at 6:37 Comment(3)
it works for both deployment and debugingHandmedown
not loading for google places API for flutter webStimson
it will make the image and text density so bad...please don't use that type of renderingCraquelure
S
38

Simply add this in your Flutter (web/index.html):

<script type="text/javascript">
    window.flutterWebRenderer = "html";
</script>
Superabundant answered 12/2, 2022 at 23:27 Comment(3)
The side effect of this approach is that the web version (at least for me) stopped rendering the Google font in the project :/ (as of Flutter 3.3.5)Hornsby
But Lottie Animation not works If I use this RendererHognut
add this script inside <head> HERE </head> sectionNevsa
T
31

For me this worked:

flutter run -d chrome --web-renderer html
Tsana answered 4/3, 2021 at 19:41 Comment(2)
The arguments work when deployed. You just need to add the same arguments during build flutter build web --web-renderer htmlGirosol
@Girosol #76412380Consign
G
29

If you use Firebase storage just follow these steps:

  1. Open Google Cloud Console at your project.

  2. Click on console icon in top right corner.

  3. Click Open editor.

  4. Click File->New->cors.json.

  5. Place code below:

    [
      {
        "origin": ["*"],
        "method": ["GET"],
        "maxAgeSeconds": 3600
      }
    ]
    
  6. Then Run in console:

    gsutil cors set cors.json gs://bucket-name
    

    bucket-name is the name of the storage bucket which you can find on your Firebase project above the folders in the storage section.

Grande answered 1/7, 2021 at 9:4 Comment(1)
To verify: 'gsutil cors get gs://your-bucket'Wendt
G
11

To debug quickly, instead of flutter run -d chrome --web-renderer html running from the terminal you can also add the arguments --web-renderer html on your run config. On the menu bar, navigate through Run > Edit Configurations

Run config

Girosol answered 11/9, 2021 at 6:18 Comment(0)
P
8

If you can't update CORS settings or add proxy, prefer CanvasKit (has better performance) over HTML renderer - could display image with platform view:

import 'dart:html';
import 'package:flutter/material.dart';
import 'dart:ui' as ui;

class MyImage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    String imageUrl = "image_url";
    // https://github.com/flutter/flutter/issues/41563
    // ignore: undefined_prefixed_name
    ui.platformViewRegistry.registerViewFactory(
      imageUrl,
      (int _) => ImageElement()..src = imageUrl,
    );
    return HtmlElementView(
      viewType: imageUrl,
    );
  }
}


Plectron answered 23/4, 2021 at 19:36 Comment(1)
i want to add fit property like image widget, any idea how to add that ?Jehial
A
7

The Ultimate Solution

Use this package instead of flutter's NetworkImage.

https://pub.dev/packages/image_network

Tested on Flutter web with Canvas renderer and it works like a charm!

Aerospace answered 13/12, 2022 at 21:35 Comment(0)
T
4

This official solution worked for me on Chrome only (Source). But I had to run it first every time.

flutter run -d chrome --web-renderer html

And disabling web security also worked (Source). But the browsers will show a warning banner.

But In case you are running on a different browser than Chrome (e.g. Edge) and you want to keep 'web security' enabled. You can change the default web renderer in settings in VS Code

File ==> Preferences ==> Settings ==> Enter 'Flutter Web' in the Search Bar ==> Set the default web renderer to html

Topeka answered 25/2, 2022 at 7:13 Comment(0)
M
3

Running

flutter run --web-renderer html

solved my issue.

Marlette answered 24/2, 2021 at 14:18 Comment(1)
This command is executed every time a change is copied in Flutter ?, this command works but when re-executing the changes no longer workStatolatry
H
2

This answer includes the two main ones mentioned as well as a vital point that wasn't:

  1. LAUNCH CONFIGURATION

Select and open your launch config:

enter image description here

Note the args value:

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Flutter (lib\\main.dart)",
      "type": "dart",
      "request": "launch",
      "program": "lib\\main.dart",
      "flutterMode": "profile",
      "args": ["-d", "chrome", "--web-renderer", "html"]
    }
  ]
}

Make sure you're running the same config:

enter image description here

Now you can run the app as usual.


  1. CORS

Install gsutil and create a file cors.json with content:

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

Run gsutil cors set cors.json gs://[YOUR BUCKET]. If you later want to clear this config from your bucket change the content to [] and run again.


  1. ADD TOKEN TO NetworkImage WIDGET

This is what made it work for my rules that required authentication, as I have removed the token param from the image url. Get the user auth token (FirebaseAuth.instance.currentUser.getIdToken()) and add it to the headers arg like so:

NetworkImage(imageUrl, headers: {
  'Authorization': 'Bearer $token',
})  

Not sure what your particular situation is with "another domain" but I hope this is relevant.

Hell answered 10/7, 2023 at 10:38 Comment(0)
M
1

For someone who uses Slim Framework, just create a .htaccess file on that folder for storing images and put this line of code

Header set Access-Control-Allow-Origin *
Mephistopheles answered 7/8, 2021 at 17:23 Comment(0)
T
1

I had an issue while loading content from other domains which I don't have control over to change the CORS settings from the server-side. I have found a work-around for this problem:

  1. Go to C:\src\flutter\packages\flutter_tools\lib\src\web or navigate from your Flutter root directory to flutter\packages\flutter_tools\lib\src\web.

  2. Open chrome.dart in your text editor.

  3. Add '--disable-web-security' under the like '--disable-extensions' and save the file.

  4. Run flutter clean in your project folder and run the app.

Adding this flag might also cause some security issues.

Tapis answered 13/10, 2021 at 19:15 Comment(0)
O
1

There are a number of answers here about --web-renderer html, but this is not a good technical decision.

As a solution, the Flutter team also suggests (in addition to customizing cors in various ways):

  1. if the app has the bytes of the encoded image in memory
  2. provided as an assets
  3. stored on the same server that serves the application

The last item may be the most successful if you are configured to use Image.network. This is also quite handy if you are hosting your project on services like Github Pages.

All of these ways also mean that:

The image can be displayed using Image.memory, Image.asset, and Image.network in both HTML and CanvasKit modes.


You can read about all the methods here - Displaying images on the web | Flutter

Oversexed answered 4/10, 2023 at 13:13 Comment(4)
I am trying to parse your first sentence here. What answers are being copied, and what decisions are you finding disgusting?Lavenialaver
How many monotonous answers offer the same thing - --web-renderer html? I counted 10! Several of these 10 offer other solutions that also duplicate each other, but this still seems normal. And I'm saying that using this flag is a bad technical decision, when there is a CanvasKit render (--web-renderer canvaskit). >This renderer is fully consistent with Flutter mobile and desktop, has faster performance with higher widget density, but adds about 1.5MB in download size. CanvasKit uses WebGL to render Skia paint commands.Oversexed
OK. I've softened the edges of the remark (commenting on meta-topics in answers isn't really necessary anyway). I wonder if you could copy some of the technical content of your comment into your answer? - I don't think you mentioned the CanvasKit render in it.Lavenialaver
Thanks for softening the rough edges of my answer :) I didn't mention the CanvasKit renderer because the solution to this issue should not lie in the areas of the --web-renderer flag. No, it will certainly work, but it's not the best solution. And thanks for the information.Oversexed
P
0

This issue will occur by CROS policy. and There is two case to handle this:

  1. For Debug
  2. For Live Web App

For Debugging I suggest just disable the web Security to Pass through CROS. or use flutter_cors package. This package only work for debugging.

For Publishing, I suggest use Proxy server to handle the CORS issue.It is a best way to Bypass CORS. Or You can try some other methods -Link Here

Photocopy answered 31/5, 2023 at 10:0 Comment(0)
H
-1

There are two ways to solve this issue:

  1. Just run your flutter web with

    flutter run -d chrome --web-renderer html
    

    But there is one problem when you render your canvas view to HTML view. All your views like images, text, etc. will come out blurry (bad quality). If you can sacrifice the quality, go on with the first solution.

  2. If you don't want to sacrifice quality, you need to add some code to your backend site. I have done with NodeJS, you can use with yours:

    var express = require("express")
    var app = express()
    
    var subsriberRecord = require("./controller/Subscribe")
    var blogRecord = require("./controller/BlogContent")
    
    app.use(function(req, res, next) {
        res.header("Access-Control-Allow-Origin", "*");
        res.header("Access-Control-Allow-Headers",
         "Origin, X-Requested-With, Content-Type, Accept"
         );
        next();
      });
    
    app.use("/record/", subsriberRecord);
    app.use("/record/", blogRecord);
    app.use('/uploads', express.static('./uploads'));
    
    app.listen(5000, () => {
        console.log("Server running at port 5000");
    })
    
Hanson answered 11/7, 2021 at 13:47 Comment(1)
Please read How to Answer and edit your answer to contain an explanation as to why this code would actually solve the problem at hand. Always remember that you're not only solving the problem, but are also educating the OP and any future readers of this post.Passover

© 2022 - 2024 — McMap. All rights reserved.