Flutter 网络请求框架封装详解
flutter 请求网络的三种方式
flutter 请求网络的方式有三种,分别是 dart 原生的网络请求 httpclient、第三方网络请求 http以及 flutter 中的 dio。我们可以比较一下这三种网络请求方式,然后封装为我们方便请求网络的工具类。
dart 原生的网络请求 httpclient
实现 dart 获取网络数据的请求,一般我们需要以下几个步骤:
step 1: 原生的网络请求时不需要修改 pubspec.yaml 文件的,我们只需要在使用的地方引入所需包就可以了
import 'dart:convert'; import 'dart:io';
step 2:创建一个httpclient
httpclient httpclient = new httpclient();
step 3: 打开http连接,设置请求头
httpclientrequest request = await httpclient.geturl(uri);
在这一步中,我们可以设置人意的的请求方法,比如 get 请求、post 请求、delete 请求。
例如:携带参数的请求
uri uri=uri(scheme: "https", host: "flutterchina.club", queryparameters: { "username":"chen", "password":"123456" });
例如:设置请求的 header
request.headers.add("user-agent", "test"); request.headers.add("authorization", "lksjdlfjsdlkjslkklsdj");
step 4: 等待连接服务器
httpclientresponse response = await request.close();
step 5: 读取响应内容
if (response.statuscode == httpstatus.ok) { _content = await response.transform(utf8decoder()).join(); }
step 6: 断开连接
httpclient.close();
以上的步骤是 dart 简单获取网络的方式,我们从上面可以看到,通过 httpclient 发起网络请求时比较麻烦的,很多都要我们亲手处理,还有 cookie 的管理也是比较麻烦的。
库 http step
1:pubspec.yaml 添加依赖
http: '>=0.11.3+12'
step 2: 在使用的地方导包
import 'package:http/http.dart' as http;
step 3: 发起请求
get 请求
void getrequest() async { var client = http.client(); http.response response = await client.get(url_2); _content = response.body; }
post 请求
void postrequest() async { var params = map<string, string>(); params["username"] = "hellonews"; params["password"] = "123456"; var client = http.client(); var response = await client.post(url_post, body: params); _content = response.body; }
相对比 dart 原生的网络请求,第三方库 http 的网络请求方式是要方便好多,写起来也是挺爽的。
flutter 发布的 dio
dio 一个强大的 dart http 请求库,支持 restful api、formdata、拦截器、请求取消、cookie管理、文件上传/下载、超时等...
step 1:pubspec.yaml 添加依赖
dependencies: dio: ^1.0.9
step 2:导入引用包
import 'package:dio/dio.dart';
step 3:发起网络请求
get 请求
void getrequest() async { dio dio = new dio(); var response = await dio.get("/test?id=12&name=chen"); _content = response.data.tostring(); }
对于 query 参数,我们可以通过对象来进行传递,上面的代码等同于:
void getrequest() async { dio dio = new dio(); var response = await dio.get("/test",data:{"id":12,"name":"chen"}); _content = response.data.tostring(); }
post 请求
void postrequest() async { var dio = new dio(); var response = await dio.post(url_post, data:{"id":12,"name":"wendu"}); _content = response.data.tostring(); }
dio 网络请求框架封装
日志信息拦截
dio 和 okhttp 一样,都会有一个请求拦截器和响应拦截器,通过拦截器,我们可以在请求之前或响应之后做一些同意的预处理。例如我们发起请求前查看我们请求的参数和头部,响应的时候,我们可以查看返回来的数据。
dio dio = new dio(); // 添加拦截器 if (config.debug) { dio.interceptors.add(interceptorswrapper( onrequest: (requestoptions options){ print("\n================== 请求数据 =========================="); print("url = ${options.uri.tostring()}"); print("headers = ${options.headers}"); print("params = ${options.data}"); }, onresponse: (response response){ print("\n================== 响应数据 =========================="); print("code = ${response.statuscode}"); print("data = ${response.data}"); print("\n"); }, onerror: (dioerror e){ print("\n================== 错误响应数据 ======================"); print("type = ${e.type}"); print("message = ${e.message}"); print("stacktrace = ${e.stacktrace}"); print("\n"); } )); }
如果我们想要移除拦截器,那么我们可以将其设置为 null
dio.interceptor.request.onsend=null; dio.interceptor.response.onsuccess=null; dio.interceptor.response.onerror=null;
token 添加
// 头部添加 token 验证 headers["authorization"] = "token lskjdlklsjkdklsjd333"; option.headers = headers; ///超时 option.connecttimeout = 15000; try { response response = await dio.request(url, data: params, options: option); } on dioerror catch (e) { // 请求错误处理 }
自动生成 dart 的 json 实体类插件 flutterjsonbeanfactory
在 android 开发中,有 gsonformat 这个插件来讲 json 数据自动转化成 bean;那么在 flutter 中也有类似的插件可以生产序列化的实体类的插件:flutterjsonbeanfactory
step 1:下载插件 flutterjsonbeanfactory,安装完成后重启
setting -> plugins -> browse respositories 中搜索 flutterjsonbeanfactory
step 2:创建实体类,在指定目录下:
new -> dart bean class file from json
step 3:输入实体类名及 json 格式的数据
step 4:最后生成的实体类:loginentity
class loginentity { string easemobpassword; string username; loginentity({this.easemobpassword, this.username}); loginentity.fromjson(map<string, dynamic> json) { easemobpassword = json['easemobpassword']; username = json['username']; } map<string, dynamic> tojson() { final map<string, dynamic> data = new map<string, dynamic>(); data['easemobpassword'] = this.easemobpassword; data['username'] = this.username; return data; } }
请求错误处理
response response; try { response = await dio.request(url, data: params, options: option); } on dioerror catch (e) { // 请求错误处理 response errorresponse; if (e.response != null) { errorresponse = e.response; } else { errorresponse = new response(statuscode: 666); } if (e.type == dioerrortype.connect_timeout) { errorresponse.statuscode = code.network_timeout; } if (config.debug) { print('请求异常: ' + e.tostring()); print('请求异常 url: ' + url); } return new resultdata(code.errorhandlefunction(errorresponse.statuscode, e.message, notip), false, errorresponse.statuscode); }
其中 resultdata 是网络结果处理的实体类
/** * 网络结果数据 * created by chenjianrun * date: 2018-07-16 */ class resultdata { var data; bool result; int code; var headers; resultdata(this.data, this.result, this.code, {this.headers}); }
code 是处理网络错误的编码,并将错误结果通过 eventbus 发送出去,一般我们可以在 main_pager 中注册监听这个事件。
///网络请求错误编码 class code { ///网络错误 static const network_error = -1; ///网络超时 static const network_timeout = -2; ///网络返回数据格式化一次 static const network_json_exception = -3; static const success = 200; static final eventbus eventbus = new eventbus(); static errorhandlefunction(code, message, notip) { if(notip) { return message; } eventbus.fire(new httperrorevent(code, message)); return message; } }
完成的网络请求类:httprequest
import 'dart:io'; import 'package:dio/dio.dart'; import 'package:private_tutor/common/sputils.dart'; import 'package:connectivity/connectivity.dart'; import 'dart:collection'; import 'package:private_tutor/common/config/config.dart'; import 'package:private_tutor/net/resultcode.dart'; import 'package:private_tutor/net/resultdata.dart'; ///http请求管理类,可单独抽取出来 class httprequest { static string _baseurl; static const content_type_json = "application/json"; static const content_type_form = "application/x-www-form-urlencoded"; static map optionparams = { "timeoutms": 15000, "token": null, "authorizationcode": null, }; static setbaseurl(string baseurl){ _baseurl = baseurl; } static get(url,param) async{ return await request(_baseurl+url, param, null, new options(method:"get")); } static post(url,param) async{ return await request(_baseurl+url, param, {"accept": 'application/vnd.github.version.full+json'}, new options(method: 'post')); } static delete(url,param) async{ return await request(_baseurl+url, param, null, new options(method: 'delete')); } static put(url,param) async{ return await request(_baseurl+url, param, null, new options(method: "put", contenttype: contenttype.text)); } ///发起网络请求 ///[ url] 请求url ///[ params] 请求参数 ///[ header] 外加头 ///[ option] 配置 static request(url, params, map<string, string> header, options option, {notip = false}) async { //没有网络 var connectivityresult = await (new connectivity().checkconnectivity()); if (connectivityresult == connectivityresult.none) { return new resultdata(code.errorhandlefunction(code.network_error, "", notip), false, code.network_error); } map<string, string> headers = new hashmap(); if (header != null) { headers.addall(header); } //授权码 if (optionparams["authorizationcode"] == null) { var authorizationcode = await getauthorization(); if (authorizationcode != null) { optionparams["authorizationcode"] = authorizationcode; } } headers["authorization"] = optionparams["authorizationcode"]; // 设置 baseurl if (option != null) { option.headers = headers; } else{ option = new options(method: "get"); option.headers = headers; } ///超时 option.connecttimeout = 15000; dio dio = new dio(); // 添加拦截器 if (config.debug) { dio.interceptors.add(interceptorswrapper( onrequest: (requestoptions options){ print("\n================== 请求数据 =========================="); print("url = ${options.uri.tostring()}"); print("headers = ${options.headers}"); print("params = ${options.data}"); }, onresponse: (response response){ print("\n================== 响应数据 =========================="); print("code = ${response.statuscode}"); print("data = ${response.data}"); print("\n"); }, onerror: (dioerror e){ print("\n================== 错误响应数据 ======================"); print("type = ${e.type}"); print("message = ${e.message}"); print("stacktrace = ${e.stacktrace}"); print("\n"); } )); } response response; try { response = await dio.request(url, data: params, options: option); } on dioerror catch (e) { // 请求错误处理 response errorresponse; if (e.response != null) { errorresponse = e.response; } else { errorresponse = new response(statuscode: 666); } if (e.type == dioerrortype.connect_timeout) { errorresponse.statuscode = code.network_timeout; } if (config.debug) { print('请求异常: ' + e.tostring()); print('请求异常 url: ' + url); } return new resultdata(code.errorhandlefunction(errorresponse.statuscode, e.message, notip), false, errorresponse.statuscode); } try { if (option.contenttype != null && option.contenttype.primarytype == "text") { return new resultdata(response.data, true, code.success); } else { var responsejson = response.data; if (response.statuscode == 201 && responsejson["token"] != null) { optionparams["authorizationcode"] = 'token ' + responsejson["token"]; await sputils.save(config.token_key, optionparams["authorizationcode"]); } } if (response.statuscode == 200 || response.statuscode == 201) { return resultdata(response.data, true, code.success, headers: response.headers); } } catch (e) { print(e.tostring() + url); return resultdata(response.data, false, response.statuscode, headers: response.headers); } return new resultdata(code.errorhandlefunction(response.statuscode, "", notip), false, response.statuscode); } ///清除授权 static clearauthorization() { optionparams["authorizationcode"] = null; sputils.remove(config.token_key); } ///获取授权token static getauthorization() async { string token = await sputils.get(config.token_key); if (token == null) { string basic = await sputils.get(config.user_basic_code); if (basic == null) { //提示输入账号密码 } else { //通过 basic 去获取token,获取到设置,返回token return "basic $basic"; } } else { optionparams["authorizationcode"] = token; return token; } } }
使用示例
/// 登录 model class loginmodel{ // 手机号码登录 static phonelogin(string phone,string verifycode) async{ resultdata response = await httprequest.post(address.phonelogin, {"phonenum" : phone,"captcha":verifycode}); if(response != null && response.result){ phoneloginentity phoneloginentity = phoneloginentity.fromjson(json.decode(response.data)); return new dataresult(phoneloginentity, true); }else{ return new dataresult(null, false); } } // 获取验证码 static getverifycode(string phone) async{ resultdata response = await httprequest.get("${address.getverifycode}?phone=${phone}", null); // var response = await httprequest.get(address.getverifycode, {"phone":phone}); if(response != null && response.result){ verifycodeentity entity = verifycodeentity.fromjson(response.data); return new dataresult(entity, true); }else{ return new dataresult(null, false); } } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。