1. 报错403提示错误
======== 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/GvYw==/xx6.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/GvYw==/xx6.jpg", scale: 1.0)
Image key: NetworkImage("https://p2.music.126.net/GvYw==/xx6.jpg", scale: 1.0)
=====================================================================================
浏览器可以正常访问图片资源,flutter使用NetworkImage加载图片报错,是因为服务器设置防伪链,导致客户端使用NetworkImage()请求图片时被服务器拒绝;
2. 解决方法
2.1 导入dio请求依赖
```
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
dio: ^5.3.3
2.2 创建一个自定义请求类封装dio,使其get请求接口暴露给使用者,来达到我们想要的自定义模拟请求头
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();
2.3 在需要调用的地方使用我们定义好的get_bytes函数来获取二进制字节数据,用于构建图片,这里要注意的是 responseType:ResponseType.bytes 这一句,设置返回响应体为我们想要的 Uint8List 数据类型然后我们在需要构建组件的地方,使用 FutureBuilder 来异步构建组件模块
import 'dart:convert';
import 'package:flutter/material.dart';
class IndexBanner extends StatelessWidget {
const IndexBanner({super.key});
@override
Widget build(BuildContext context) {
return const BannerContent();
}
}
class BannerContent extends StatefulWidget {
const BannerContent({super.key});
@override
State<BannerContent> createState() => _BannerContentState();
}
class _BannerContentState extends State<BannerContent> {
final _bannerData = [];
int bannerCount = 0;
@override
void initState() {
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.topLeft,
height: 200,
child: _bannerData.length > 0? Swiper(
itemBuilder: (BuildContext context,int index){
return Container(
padding: const EdgeInsets.all(8),
child: Container(
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8)
),
child: FutureBuilder(
future: ssjRequestManager.get_bytes(_bannerData[index].pic,{}),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if(snapshot.connectionState == ConnectionState.done){
return Image.memory(snapshot.data,fit: BoxFit.fill);
}else {
return const Icon(Icons.file_download);
// return const Icon();
}
}
),
)
);
},
itemCount: _bannerData.length,
// itemCount: 5,
loop: true, // 无缝循环
autoplay: true, // 自动播放
pagination: const SwiperPagination(
margin: EdgeInsets.only(bottom: 20),
builder: DotSwiperPaginationBuilder(
size: 8, // 未选中的大小
activeSize: 8, // 选中的大小
color: Color.fromRGBO(0, 0, 0, 0.08), // 未选中的颜色
activeColor: Color.fromRGBO(255, 0, 0, 1)
)
),
control: null,
): const SizedBox(
height: 200,
child: Text(''),
),
);
}
}