Flutter Image.network() reports 403 error when loading images

Flutter error 403 reasons

======== Exception caught by image resource service ================================================
The following NetworkImageLoadException was thrown resolving an image codec:
HTTP request failed, statusCode: 403, https://p2.music.126.net/GvYQoflE99eoeGi9jG4Bsw==/109951165375336156.jpg

When the exception was thrown, this was the stack: 
#0      NetworkImage._loadAsync (package:flutter/src/painting/_network_image_io.dart:150:9)
<asynchronous suspension>
Image provider: NetworkImage("https://p2.music.126.net/GvYQoflE99eoeGi9jG4Bsw==/109951165375336156.jpg", scale: 1.0)
Image key: NetworkImage("https://p2.music.126.net/GvYQoflE99eoeGi9jG4Bsw==/109951165375336156.jpg", scale: 1.0)
====================================================================================================

 Flutter gets a 403 error when loading images. However, accessing this URL through a browser can be accessed normally. The reason is that the server has set up anti-counterfeiting chain measures, causing the server to reject the client's request when using Image.network() to load images.


Solutions

Refer


Referer is a field in the HTTP request header, which records the page address from which the current requested page comes. Through this field, we can track the source of the visitor and understand the link from which page they came to the current page.

Anti-hotlinking


When users browse the web, if they click on a link or image to jump to a new page, the URL of the previous page will be automatically included in the HTTP request header as the Referer field. For image requests, Referer usually refers to the URL of the web page where the image is located. The browser automatically adds the Referer field to requests made so that the server can understand how the user arrived at the current page.

For example, I put the image file on Gitee, and then I wrote a client to call it every time. This is equivalent to borrowing Gitee's server resources. These service resources require payment, and I get from them interests. This behavior is equivalent to hotlinking.

Usually server anti-hotlink technology generally has the following methods:

  • Determined by the Referer in the request header
  • Determine by checking Cookie and Session
  • By regularly modifying file names and file links

Ideas


Since we already know that the server determines whether it has permission to access the image resource based on the Referer content requested by the client, we can remove the Referer in the request header to simulate the initial use of a browser to access the image resource and avoid being retrieved by the server. Hotlink.

Solution


Customize the request header through http request, first import the dio dependency

dependencies:
  flutter:
    sdk: flutter
  #网络请求包
  dio: ^5.3.3

Create a custom request class in the lib directory to encapsulate dio and expose its get request interface to users to achieve the custom simulation request header we want.

import 'dart:typed_data';
import 'package:dio/dio.dart';

const String bytes_user_agent =
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36 Edg/118.0.2088.76";

class SSJRequestManager {
  final Dio _dio = Dio();

  Dio getDio() {
    return _dio;
  }

  SSJRequestManager();

  // 获取二进制数据
  Future<Uint8List> get_bytes(String path, Map<String, dynamic> params) async {
    var options = Options(
        method: "GET",
        responseType: ResponseType.bytes,
        headers: {"User-Agent": bytes_user_agent});

    return await _dio
        .get(path, queryParameters: params, options: options)
        .then((value) => value.data);
  }
}

final SSJRequestManager ssjRequestManager = SSJRequestManager();

Then use the get_bytes function we defined where it needs to be called to obtain binary byte data for building pictures. What should be noted here is responseType: ResponseType.bytes < /span>  to build component modules asynchronouslyFutureBuilder  and then where we need to build the component, Use Uint8List  In this sentence, set the return response body to the data type we want     

import 'package:flutter/material.dart';
import 'package:yqplaymusic/common/utils/request.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: Scaffold(
        body: Center(
          child: SizedBox(
            height: 100,
            width: 100,
            child: FutureBuilder(
              future: ssjRequestManager.get_bytes(
                  "http://p2.music.126.net/GvYQoflE99eoeGi9jG4Bsw==/109951165375336156.jpg",
                  {}),
              builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
                if(snapshot.connectionState == ConnectionState.done)
                  {
                    return Image.memory(snapshot.data);
                  }
                else
                  {
                     return const Icon(Icons.file_download);
                    //return Image.network("https://p2.music.126.net/GvYQoflE99eoeGi9jG4Bsw==/109951165375336156.jpg");
                  }
              },
            ),
          ),
        ),
      ),
    );
  }
}

Guess you like

Origin blog.csdn.net/qianxiamuxin/article/details/134190195