Надпись—— Держа меч в мире, начиная со своего накопления, куда бы вы ни пошли, вы должны стремиться к совершенству, то есть подбрасывать каждый день.
важная новость
- Анализ использования диодов сетевых запросов во флаттере Видеоурок здесь
- Flutter: от начальной практики до разработки видео с основами пользовательского интерфейса приложения
- Основы разработки Flutter от практики входа до разработки приложения
- Серия статей по пошаговому анализу кроссплатформенной разработки Flutter находится здесь
В этой статье будет описано 1. Используйте dio для отправки базового запроса на получение 2. Используйте dio для отправки метода параметра запроса на получение 3. Разберите ответные данные json 4. Используйте dio для отправки почтового запроса и отправки параметров FormData 5. Используйте dio для отправки почтового запроса и отправки параметров json. 6. Используйте dio для загрузки файлов и реализации мониторинга прогресса 7. Используйте dio для загрузки файлов и реализации мониторинга прогресса 8. Настраиваем перехватчик dio 9. Настройте сетевой прокси-сервер dio для захвата пакетов. 10. Настройте заголовок запроса dio и параметры публичного запроса. 11.dio отменяет сетевой запрос
1. Введение
dio — это фреймворк, используемый для доступа к сети в кроссплатформенной разработке флаттера, при его использовании мы сначала вводим зависимости
dio: 3.0.9
2 Дио получить запрос
2.1 Dio получить запрос без параметров
//get请求无参数
void getRequestFunction1() async {
///创建Dio对象
Dio dio = new Dio();
///请求地址 获取用户列表
String url = "http://192.168.0.102:8080/getUserList";
///发起get请求
Response response = await dio.get(url);
///响应数据
var data = response.data;
setState(() {
result = data.toString();
});
}
результат ответа данных
{
"code": 200,
"data": [
{
"id": 3,
"userName": "测试人员",
"realName": "张三",
"age": 22
}
],
"message": "请求成功"
}
Отладка точки останова выглядит следующим образом
2.2 Запрос Dio get имеет параметры
///get请求有参数
///根据用户ID来获取用户信息
void getRequestFunction2() async {
///用户id
int userId =3;
///创建 dio
Dio dio = new Dio();
///请求地址
///传参方式1
String url = "http://192.168.0.102:8080/getUser/$userId";
///传参方式2
String url2 = "http://192.168.0.102:8080/getUser?userId=$userId";
///传参方式 3
String url3 = "http://192.168.0.102:8080/getUser";
Map<String,dynamic> map = Map();
map["userId"]= userId;
///发起get请求
Response response = await dio.get(url3,queryParameters: map);
///响应数据
Map<String,dynamic> data = response.data;
/// 将响应数据解析为 UserBean
UserBean userBean = UserBean.fromJson(data);
}
}
В приведенном выше коде режим передачи параметров 1 и режим передачи параметров 2 представляют собой параметры сплайсинга в ссылке запроса, режим запроса 3 заключается в том, чтобы поместить параметры в карту, а затем настроить параметры с помощью параметров запроса Дио.. Структура данных, возвращенная выше, выглядит так:
{
"code": 200,
"data": {
"id": 3,
"userName": "测试人员",
"realName": "张三",
"age": 22
},
"message": "请求成功"
}
отладка точки останова
Для используемого здесь объекта модели данных UserBean
class UserBean{
String userName;
String realName;
int age;
int id;
static UserBean fromJson(Map<String,dynamic> rootData){
///解析第一层
Map<String,dynamic> data = rootData["data"];
///解析第二层
UserBean userBean = new UserBean();
userBean.id = data["id"];
userBean.age = data["age"];
userBean.userName= data["userName"];
userBean.realName = data["realName"];
return userBean;
}
}
Для анализа данных в UserBean, как показано ниже
3 Почтовый запрос Дио
2.1 Почтовый запрос Dio для отправки данных формы FormData
FormData объединяет переданное имя параметра и значение для сериализации данных формы, тем самым уменьшая сращивание элементов формы. Его также можно описать следующим образом: интерфейс FormData предоставляет способ создания пар ключ-значение, представляющих данные формы.Тип кодирования запроса, отправляемого через FormData, устанавливается на «multipart/form-data», а в доступе к сетевому запросу — через Content -Type для записи этого значения, можно понять, что Content-Type представляет информацию о типе мультимедиа в конкретном запросе.
И Content-Type, который мы обычно используем в реальной разработке, выглядит следующим образом:
multipart/form-data
application/json JSON数据格式
application/x-www-form-urlencoded 表单数据格式
Далее мы будем использовать dio для инициирования почтового запроса, а формат передаваемых параметров — FromData.
void postRequestFunction() async {
///创建Dio
Dio dio = new Dio();
///发送 FormData:
FormData formData = FormData.fromMap({"name": "张三", "age": 22});
String url ="http://192.168.200.68:8080/registerUser";
///发起 post 请求 如这里的注册用户信息
Response response = await dio
.post(url, data: formData);
result = response.data.toString();
setState(() {});
}
Захват пакета выглядит следующим образом
Мы также можем увидеть формат параметраЗдесь мы видим, что Content-type имеет значение text/plain, а не multipart/form-data, как мы сказали выше, потому что при инкапсуляции параметров через FormData Dio будет выполняться настройка по умолчанию, как показано на рисунке ниже.2.2 Почтовый запрос Dio для отправки данных json
Затем мы используем dio для инициирования почтового запроса и отправки параметров в формате json.
///post请求发送json
void postRequestFunction2() async{
String url = "http://192.168.0.102:8080/registerUser2";
///创建Dio
Dio dio = new Dio();
///创建Map 封装参数
Map<String,dynamic> map = Map();
map['userName']="小明";
map['userAge']=44;
///发起post请求
Response response = await dio.post(url,data: map);
var data = response.data;
}
Захват пакета выглядит следующим образом
На рисунке выше мы видим, что Content-Type указывает, что метод передачи параметра отправляется в формате json, На рисунке ниже мы видим конкретные параметры4 Загрузка файлов Dio и мониторинг прогресса
///手机中的图片
String localImagePath ="/storage/emulated/0/Download/17306285.jpg";
///上传的服务器地址
String netUploadUrl = "http://192.168.0.102:8080/fileupload";
///dio 实现文件上传
void fileUplod() async{
///创建Dio
Dio dio = new Dio();
Map<String ,dynamic> map = Map();
map["auth"]="12345";
map["file"] = await MultipartFile.fromFile(localImagePath,filename: "xxx23.png");
///通过FormData
FormData formData = FormData.fromMap(map);
///发送post
Response response = await dio.post(netUploadUrl, data: formData,
///这里是发送请求回调函数
///[progress] 当前的进度
///[total] 总进度
onSendProgress: (int progress, int total) {
print("当前进度是 $progress 总进度是 $total");
},);
///服务器响应结果
var data = response.data;
}
Отладка с точками останова
Интерфейс запроса загрузки изображения здесь возвращает путь сохранения изображения, мы открываем каталог локального сервера5 Загрузка файлов Dio и мониторинг прогресса
///当前进度进度百分比 当前进度/总进度 从0-1
double currentProgress =0.0;
///下载文件的网络路径
String apkUrl ="";
///使用dio 下载文件
void downApkFunction() async{
/// 申请写文件权限
bool isPermiss = await checkPermissFunction();
if(isPermiss) {
///手机储存目录
String savePath = await getPhoneLocalPath();
String appName = "rk.apk";
///创建DIO
Dio dio = new Dio();
///参数一 文件的网络储存URL
///参数二 下载的本地目录文件
///参数三 下载监听
Response response = await dio.download(
apkUrl, "$savePath$appName", onReceiveProgress: (received, total) {
if (total != -1) {
///当前下载的百分比例
print((received / total * 100).toStringAsFixed(0) + "%");
// CircularProgressIndicator(value: currentProgress,) 进度 0-1
currentProgress = received / total;
setState(() {
});
}
});
}else{
///提示用户请同意权限申请
}
}
Разрешения Android в настоящее время делятся на три типа: обычные разрешения, опасные разрешения и специальные разрешения.
Обычные разрешения Разрешения, которые можно получить, настроив непосредственно в файле AndroidManifest. Большинство разрешений находятся здесь. Опасные разрешения, некоторые разрешения определены здесь после Android 6.0. Опасные разрешения нужно не только настроить в AndroidManifest, но и проверить, действительно ли у них есть разрешения, прежде чем использовать их для динамического применения к ним.
В ios используйте xcode, чтобы открыть этот каталог
Выберите файл info.plist в проекте Xcode, щелкните правой кнопкой мыши и выберите «Открыть как — исходный код» и скопируйте в него код конфигурации разрешений.Содержимое пары «ключ-значение» можно изменить в соответствии с требованиями проекта.
<!-- 相册 -->
<key>NSPhotoLibraryUsageDescription</key>
<string>需要您的同意,APP才能访问相册</string>
<!-- 相机 -->
<key>NSCameraUsageDescription</key>
<string>需要您的同意,APP才能访问相机</string>
<!-- 麦克风 -->
<key>NSMicrophoneUsageDescription</key>
<string>需要您的同意,APP才能访问麦克风</string>
<!-- 位置 -->
<key>NSLocationUsageDescription</key>
<string>需要您的同意, APP才能访问位置</string>
<!-- 在使用期间访问位置 -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>App需要您的同意, APP才能在使用期间访问位置</string>
<!-- 始终访问位置 -->
<key>NSLocationAlwaysUsageDescription</key>
<string>App需要您的同意, APP才能始终访问位置</string>
<!-- 日历 -->
<key>NSCalendarsUsageDescription</key>
<string>App需要您的同意, APP才能访问日历</string>
<!-- 提醒事项 -->
<key>NSRemindersUsageDescription</key>
<string>需要您的同意, APP才能访问提醒事项</string>
<!-- 运动与健身 -->
<key>NSMotionUsageDescription</key>
<string>需要您的同意, APP才能访问运动与健身</string>
<!-- 健康更新 -->
<key>NSHealthUpdateUsageDescription</key>
<string>需要您的同意, APP才能访问健康更新 </string>
<!-- 健康分享 -->
<key>NSHealthShareUsageDescription</key>
<string>需要您的同意, APP才能访问健康分享</string>
<!-- 蓝牙 -->
<key>NSBluetoothPeripheralUsageDescription</key>
<string>需要您的同意, APP才能访问蓝牙</string>
<!-- 媒体资料库 -->
<key>NSAppleMusicUsageDescription</key>
<string>需要您的同意, APP才能访问媒体资料库</string>
В каталоге проекта флаттера мы также можем открыть конфигурацию файла info.plist, как показано ниже.
Плагин разрешения_обработчика используется здесь для подачи заявок на разрешенияpermission_handler: ^4.3.0
Запрос кода доступа выглядит следующим образом
///PermissionGroup.storage 对应的是
///android 的外部存储 (External Storage)
///ios 的Documents` or `Downloads`
checkPermissFunction() async {
if (Theme.of(context).platform == TargetPlatform.android) {
///安卓平台中 checkPermissionStatus方法校验是否有储存卡的读写权限
PermissionStatus permission = await PermissionHandler()
.checkPermissionStatus(PermissionGroup.storage);
if (permission != PermissionStatus.granted) {
///无权限那么 调用方法 requestPermissions 申请权限
Map<PermissionGroup, PermissionStatus> permissions =
await PermissionHandler()
.requestPermissions([PermissionGroup.storage]);
///校验用户对权限申请的处理
if (permissions[PermissionGroup.storage] == PermissionStatus.granted) {
return true;
}
} else {
return true;
}
} else {
return true;
}
return false;
}
После подачи заявки на разрешение нам нужно определить путь к карте памяти, здесь мы используем плагин path_provider.
path_provider: 1.6.0
///获取手机的存储目录路径
///getExternalStorageDirectory() 获取的是 android 的外部存储 (External Storage)
/// getApplicationDocumentsDirectory 获取的是 ios 的Documents` or `Downloads` 目录
Future<String> getPhoneLocalPath() async {
final directory = Theme.of(context).platform == TargetPlatform.android
? await getExternalStorageDirectory()
: await getApplicationDocumentsDirectory();
return directory.path;
}
6 dio настраивает сетевой прокси для захвата пакетов
_setupPROXY(Dio dio) {
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(HttpClient client) {
client.findProxy = (uri) {
///这里的 192.168.0.102:8888就是我们的代理服务地址
return "PROXY 192.168.0.102:8888";
};
client.badCertificateCallback =
(X509Certificate cert, String host, int port) {
return true;
};
};
}
7 dio настраивает параметры публичного запроса
В реальной разработке приложения у нас будут параметры, которые необходимо передавать для каждого запроса интерфейса, такие как токен, appVersionCode и т. д., которые называются параметрами публичного запроса, тогда мы можем рассмотреть эту конфигурацию в запросе dio здесь
String application = "V 1.2.2";
int appVersionCode = 122;
///[url]网络请求链接
///[data] post 请求时传的json数据
///[queryParameters] get请求时传的参数
void configCommonPar(url,data,Map<String, dynamic> queryParameters){
///配制统一参数
if (data != null) {
data['application'] = application;
data['appVersionCode'] = appVersionCode.toString();
} else if (queryParameters != null) {
queryParameters['application'] = application;
queryParameters['appVersionCode'] = appVersionCode.toString();
} else {
///url中有可能拼接着其他参数
if (url.contains("?")) {
url += "&application=$application&appVersionCode=$appVersionCode";
} else {
url += "?application=$application&appVersionCode=$appVersionCode";
}
}
}
}
8 dio настраивает Content-Type и заголовок запроса
Когда мы создаем объект Dio, мы инициализируем BaseOptions для создания Dio.
BaseOptions options = BaseOptions();
///请求header的配置
options.headers["appVersionCode"]=406;
options.headers["appVersionName"]="V 4.0.6";
options.contentType="application/json";
options.method="GET";
options.connectTimeout=30000;
///创建 dio
Dio dio = new Dio(options);
Мы также можем получить параметры по умолчанию через dio и изменять их каждый раз, когда отправляем разные запросы, такие как get и post.
void getRequestFunction2() async {
///用户id
int userId = 3;
///创建 dio
Dio dio = new Dio();
///请求地址
///传参方式1
String url = "http://192.168.0.102:8080/getUser/$userId";
///在这里修改 contentType
dio.options.contentType="application/json";
///请求header的配置
dio.options.headers["appVersionCode"]=406;
dio.options.headers["appVersionName"]="V 4.0.6";
///发起get请求
Response response = await dio.get(url);
...
}
9 dio отменяет сетевой запрос
В реальной разработке, например, когда мы выходим со страницы, если сетевой запрос не выполнен, это вызовет утечку памяти, поэтому необходимо отменить сетевой запрос, когда страница будет уничтожена, или при загрузке файла, время слишком велико, и пользователь нажимает кнопку «Отмена», чтобы отменить сетевое подключение.
///创建取消标志
CancelToken cancelToken = new CancelToken();
void getRequestFunction2() async {
///用户id
int userId = 3;
///创建 dio
Dio dio = new Dio();
///请求地址
///传参方式1
String url = "http://192.168.0.102:8080/getUser/$userId";
///发起get请求 并设置 CancelToken 取消标志
Response response = await dio.get(url,cancelToken: cancelToken);
...
}
Затем, когда нам нужно вручную отменить этот сетевой запрос, нам нужно только вызвать следующий метод
///取消网络请求
if(cancelToken!=null&&!cancelToken.isCancelled){
cancelToken.cancel();
cancelToken=null;
}
Следует отметить, что CancelToken можно использовать только для одного сетевого запроса.
полный