Flutter Http網(wǎng)絡(luò)請(qǐng)求實(shí)現(xiàn)詳解
Http網(wǎng)絡(luò)請(qǐng)求是一門開發(fā)語(yǔ)言里比較常用和重要的功能,主要用于資源訪問(wèn)、接口數(shù)據(jù)請(qǐng)求和提交、上傳下載文件等等操作,Http請(qǐng)求方式主要有:GET、POST、HEAD、PUT、DELETE、TRACE、CONNECT、OPTIONS。本文主要GET和POST這兩種常用請(qǐng)求在Flutter中的用法,其中對(duì)POST將進(jìn)行著重講解。Flutter的Http網(wǎng)絡(luò)請(qǐng)求的實(shí)現(xiàn)主要分為三種:io.dart里的HttpClient實(shí)現(xiàn)、Dart原生http請(qǐng)求庫(kù)實(shí)現(xiàn)、第三方庫(kù)實(shí)現(xiàn)。后面將會(huì)給大家詳細(xì)講解這幾種區(qū)別和特點(diǎn)及前兩種的使用方法。接下來(lái),我們就開始Flutter的Http網(wǎng)絡(luò)請(qǐng)求詳解吧。
本文將主要介紹:
- 簡(jiǎn)單介紹這幾種Http請(qǐng)求方式
- Flutter三種Http網(wǎng)絡(luò)請(qǐng)求實(shí)現(xiàn)的區(qū)別和特點(diǎn)
- HttpClient實(shí)現(xiàn)Http網(wǎng)絡(luò)請(qǐng)求
- Dart原生http請(qǐng)求庫(kù)實(shí)現(xiàn)Http網(wǎng)絡(luò)請(qǐng)求
- 第三方庫(kù)的推薦
1. Http的請(qǐng)求方式簡(jiǎn)介
Http網(wǎng)絡(luò)請(qǐng)求方式就是描述了客戶端想對(duì)指定的資源或服務(wù)器所要執(zhí)行的操作。開頭簡(jiǎn)介里介紹過(guò),Http網(wǎng)絡(luò)請(qǐng)求是一門開發(fā)語(yǔ)言里比較常用和重要的功能,主要用于資源訪問(wèn)、接口數(shù)據(jù)請(qǐng)求和提交、上傳下載文件等等操作。其中主要的請(qǐng)求方式有:GET、POST、HEAD、PUT、DELETE、TRACE、CONNECT、OPTIONS這八種。接下來(lái)先簡(jiǎn)單介紹它們的特點(diǎn)和作用。
1.1 GET請(qǐng)求方式
從GET這個(gè)單詞上也可以看出,它主要是執(zhí)行獲取資源操作的,例如通過(guò)URL從服務(wù)器獲取返回的資源,其中GET可以把請(qǐng)求的一些參數(shù)信息拼接在URL上,傳遞給服務(wù)器,由服務(wù)器端進(jìn)行參數(shù)信息解析,然后返回相應(yīng)的資源給請(qǐng)求者。注意:GET請(qǐng)求拼接的URL數(shù)據(jù)大小和長(zhǎng)度是有最大限制的,傳輸?shù)臄?shù)據(jù)量一般限制在2KB。
1.2 POST請(qǐng)求方式
POST主要是執(zhí)行提交信息、傳輸信息的操作,POST請(qǐng)求的可以攜帶很多的數(shù)據(jù),而且格式不限。如JSON、XML、文本等等都支持。并且POST傳遞的一些數(shù)據(jù)和參數(shù)不是直接拼接在URL后的,而是放在Http請(qǐng)求Body里,相對(duì)GET來(lái)說(shuō)比較安全。并且傳遞的數(shù)據(jù)大小和格式是無(wú)限制的。POST請(qǐng)求方式是比較重要和常用的一種,POST請(qǐng)求包含兩部分:請(qǐng)求頭(header)和請(qǐng)求體(body)。POST請(qǐng)求常見的請(qǐng)求體(body)有三種傳輸內(nèi)容類型Content-type:application/x-www-form-urlencoded、application/json、multipart/form-data,當(dāng)然還有其他的幾種,不過(guò)不常用,常用的就是這三種。
1.3 HEAD請(qǐng)求方式
HEAD主要是執(zhí)行給請(qǐng)求的客戶端返回頭信息,而不返回Body主體內(nèi)容。和GET方式類似,只不過(guò)GET方式有Body實(shí)體返回,而HEAD只返回頭信息,無(wú)Body實(shí)體內(nèi)容返回。主要是用于確認(rèn)URL的有效性、資源更新的日期時(shí)間、查看服務(wù)器狀態(tài)等等,對(duì)于有這方面需求的請(qǐng)求來(lái)說(shuō),比較不占用資源。
1.4 PUT請(qǐng)求方式
PUT主要是執(zhí)行傳輸文件操作,類似于FTP的文件上傳一樣,請(qǐng)求里包含文件內(nèi)容,并將此文件保存到URI指定的服務(wù)器位置。和POST方式的主要區(qū)別是:PUT請(qǐng)求方式如果前后兩個(gè)請(qǐng)求相同,則后一個(gè)請(qǐng)求會(huì)把前一個(gè)請(qǐng)求覆蓋掉,實(shí)現(xiàn)了PUT方式的修改資源;而POST請(qǐng)求方式如果前后兩個(gè)請(qǐng)求相同,則后一個(gè)請(qǐng)求不會(huì)把前一個(gè)請(qǐng)求覆蓋掉,實(shí)現(xiàn)了POST的增加資源。
1.5 DELETE請(qǐng)求方式
DELETE主要是執(zhí)行告訴服務(wù)器想要?jiǎng)h除的資源,執(zhí)行刪除指定資源操作。
1.6 OPTIONS請(qǐng)求方式
OPTIONS主要是執(zhí)行查詢針對(duì)所要請(qǐng)求的URI資源服務(wù)器所支持的請(qǐng)求方式,也就是獲取這個(gè)URI所支持客戶端提交給服務(wù)器端的請(qǐng)求方式有哪些。
1.7 TRACE請(qǐng)求方式
TRACE主要是執(zhí)行追蹤傳輸路徑的操作,例如,我們發(fā)起了一個(gè)Http請(qǐng)求,在這個(gè)過(guò)程中這個(gè)請(qǐng)求可能會(huì)經(jīng)過(guò)很多個(gè)路徑和過(guò)程,TRACE就是告訴服務(wù)器在收到請(qǐng)求后,返回一條響應(yīng)信息,將它收到的原始Http請(qǐng)求信息返回給客戶端,這樣就可以確認(rèn)在Http傳輸過(guò)程中請(qǐng)求是否被修改過(guò)。
1.8 CONNECT請(qǐng)求方式
CONNECT主要就是執(zhí)行連接代理操作,例如“翻墻”??蛻舳送ㄟ^(guò)CONNECT方式與服務(wù)器建立通信隧道,進(jìn)行TCP通信。主要通過(guò)SSL和TLS安全傳輸數(shù)據(jù)。CONNECT的作用就是告訴服務(wù)器讓它代替客戶端去請(qǐng)求訪問(wèn)某個(gè)資源,然后再將數(shù)據(jù)返回給客戶端,相當(dāng)于一個(gè)媒介中轉(zhuǎn)。
2. Flutter Http網(wǎng)絡(luò)請(qǐng)求實(shí)現(xiàn)的區(qū)別和特點(diǎn)
介紹完了Http幾種請(qǐng)求方式,我們看下Flutter中的Http網(wǎng)絡(luò)請(qǐng)求的實(shí)現(xiàn)方式。Flutter的Http網(wǎng)絡(luò)請(qǐng)求的實(shí)現(xiàn)主要分為三種:io.dart里的HttpClient實(shí)現(xiàn)、Dart原生http請(qǐng)求庫(kù)實(shí)現(xiàn)、第三方庫(kù)實(shí)現(xiàn)。
我們首先看下第一種:io.dart里的HttpClient實(shí)現(xiàn)。
io.dart里的HttpClient實(shí)現(xiàn)的Http網(wǎng)絡(luò)請(qǐng)求主要是實(shí)現(xiàn)了基本的網(wǎng)絡(luò)請(qǐng)求,復(fù)雜一些的網(wǎng)絡(luò)請(qǐng)求還無(wú)法完成。例如POST里的其他幾種Body請(qǐng)求體傳輸內(nèi)容類型部分還無(wú)法支持,multipart/form-data這個(gè)類型傳輸還不支持。所以如果你的一些Http網(wǎng)絡(luò)請(qǐng)求可以通過(guò)io.dart里的HttpClient實(shí)現(xiàn)的話,用這個(gè)也可以完成要求。
那么接下來(lái)我們就看下io.dart里的HttpClient實(shí)現(xiàn)的Http網(wǎng)絡(luò)請(qǐng)求實(shí)現(xiàn)步驟。
import 'dart:convert'; import 'dart:io'; class IOHttpUtils { //創(chuàng)建HttpClient HttpClient _httpClient = HttpClient(); //要用async關(guān)鍵字異步請(qǐng)求 getHttpClient() async { _httpClient .get('https://abc.com', 8090, '/path1') .then((HttpClientRequest request) { //在這里可以對(duì)request請(qǐng)求添加headers操作,寫入請(qǐng)求對(duì)象數(shù)據(jù)等等 // Then call close. return request.close(); }).then((HttpClientResponse response) { // 處理response響應(yīng) if (response.statusCode == 200) { response.transform(utf8.decoder).join().then((String string) { print(string); }); } else { print("error"); } }); } getUrlHttpClient() async { var url = "https://abc.com:8090/path1"; _httpClient.getUrl(Uri.parse(url)).then((HttpClientRequest request) { // Optionally set up headers... // Optionally write to the request object... // Then call close. return request.close(); }).then((HttpClientResponse response) { // Process the response. if (response.statusCode == 200) { response.transform(utf8.decoder).join().then((String string) { print(string); }); } else { print("error"); } }); } //進(jìn)行POST請(qǐng)求 postHttpClient() async { _httpClient .post('https://abc.com', 8090, '/path2') .then((HttpClientRequest request) { //這里添加POST請(qǐng)求Body的ContentType和內(nèi)容 //這個(gè)是application/json數(shù)據(jù)類型的傳輸方式 request.headers.contentType = ContentType("application", "json"); request.write("{\"name\":\"value1\",\"pwd\":\"value2\"}"); return request.close(); }).then((HttpClientResponse response) { // Process the response. if (response.statusCode == 200) { response.transform(utf8.decoder).join().then((String string) { print(string); }); } else { print("error"); } }); } postUrlHttpClient() async { var url = "https://abc.com:8090/path2"; _httpClient.postUrl(Uri.parse(url)).then((HttpClientRequest request) { //這里添加POST請(qǐng)求Body的ContentType和內(nèi)容 //這個(gè)是application/x-www-form-urlencoded數(shù)據(jù)類型的傳輸方式 request.headers.contentType = ContentType("application", "x-www-form-urlencoded"); request.write("name='value1'&pwd='value2'"); return request.close(); }).then((HttpClientResponse response) { // Process the response. if (response.statusCode == 200) { response.transform(utf8.decoder).join().then((String string) { print(string); }); } else { print("error"); } }); } ///其余的HEAD、PUT、DELETE請(qǐng)求用法類似,大同小異,大家可以自己試一下 ///在Widget里請(qǐng)求成功數(shù)據(jù)后,使用setState來(lái)更新內(nèi)容和狀態(tài)即可 ///setState(() { /// ... /// }); }
第二種:Dart原生http請(qǐng)求庫(kù)實(shí)現(xiàn)。
這里推薦這種方式使用,畢竟Dart原生的http請(qǐng)求庫(kù)支持的Http請(qǐng)求比較全面,比較復(fù)雜的請(qǐng)求都可以實(shí)現(xiàn),如上傳和下載文件等等操作。
Dart目前官方的倉(cāng)庫(kù)里有大量的三方庫(kù)和官方庫(kù),引用也非常的方便,Dart PUB官方地址為:https://pub.dartlang.org。
打開后如下圖所示:
使用Dart原生http庫(kù),我們首先需要在Dart PUB或官方Github里把相關(guān)的http庫(kù)引用下來(lái)。
在Dart PUB里搜索http,便可以查找到我們的http庫(kù),根據(jù)說(shuō)明進(jìn)行引用和使用即可。
http庫(kù)官方Github庫(kù)地址為:https://github.com/dart-lang/http
點(diǎn)擊Installing,查看引用方法進(jìn)行引用即可。
在項(xiàng)目的pubspec.yaml配置文件里加入引用:
完畢,這樣就可以在dart文件類里直接import使用了。接下來(lái)給一個(gè)完整的使用例子:
import 'dart:convert'; import 'dart:io'; import 'package:http/http.dart' as http; import 'package:http_parser/http_parser.dart'; class DartHttpUtils { //創(chuàng)建client實(shí)例 var _client = http.Client(); //發(fā)送GET請(qǐng)求 getClient() async { var url = "https://abc.com:8090/path1?name=abc&pwd=123"; _client.get(url).then((http.Response response) { //處理響應(yīng)信息 if (response.statusCode == 200) { print(response.body); } else { print('error'); } }); } //發(fā)送POST請(qǐng)求,application/x-www-form-urlencoded postUrlencodedClient() async { var url = "https://abc.com:8090/path2"; //設(shè)置header Map<String, String> headersMap = new Map(); headersMap["content-type"] = "application/x-www-form-urlencoded"; //設(shè)置body參數(shù) Map<String, String> bodyParams = new Map(); bodyParams["name"] = "value1"; bodyParams["pwd"] = "value2"; _client .post(url, headers: headersMap, body: bodyParams, encoding: Utf8Codec()) .then((http.Response response) { if (response.statusCode == 200) { print(response.body); } else { print('error'); } }).catchError((error) { print('error'); }); } //發(fā)送POST請(qǐng)求,application/json postJsonClient() async { var url = "https://abc.com:8090/path3"; Map<String, String> headersMap = new Map(); headersMap["content-type"] = ContentType.json.toString(); Map<String, String> bodyParams = new Map(); bodyParams["name"] = "value1"; bodyParams["pwd"] = "value2"; _client .post(url, headers: headersMap, body: jsonEncode(bodyParams), encoding: Utf8Codec()) .then((http.Response response) { if (response.statusCode == 200) { print(response.body); } else { print('error'); } }).catchError((error) { print('error'); }); } // 發(fā)送POST請(qǐng)求,multipart/form-data postFormDataClient() async { var url = "https://abc.com:8090/path4"; var client = new http.MultipartRequest("post", Uri.parse(url)); client.fields["name"] = "value1"; client.fields["pwd"] = "value2"; client.send().then((http.StreamedResponse response) { if (response.statusCode == 200) { response.stream.transform(utf8.decoder).join().then((String string) { print(string); }); } else { print('error'); } }).catchError((error) { print('error'); }); } // 發(fā)送POST請(qǐng)求,multipart/form-data,上傳文件 postFileClient() async { var url = "https://abc.com:8090/path5"; var client = new http.MultipartRequest("post", Uri.parse(url)); http.MultipartFile.fromPath('file', 'sdcard/img.png', filename: 'img.png', contentType: MediaType('image', 'png')) .then((http.MultipartFile file) { client.files.add(file); client.fields["description"] = "descriptiondescription"; client.send().then((http.StreamedResponse response) { if (response.statusCode == 200) { response.stream.transform(utf8.decoder).join().then((String string) { print(string); }); } else { response.stream.transform(utf8.decoder).join().then((String string) { print(string); }); } }).catchError((error) { print(error); }); }); } ///其余的HEAD、PUT、DELETE請(qǐng)求用法類似,大同小異,大家可以自己試一下 ///在Widget里請(qǐng)求成功數(shù)據(jù)后,使用setState來(lái)更新內(nèi)容和狀態(tài)即可 ///setState(() { /// ... /// }); }
第三種:第三方庫(kù)實(shí)現(xiàn)。
Flutter第三方庫(kù)有很多可以實(shí)現(xiàn)Http網(wǎng)絡(luò)請(qǐng)求,例如國(guó)內(nèi)開發(fā)者開發(fā)的dio庫(kù),dio支持多個(gè)文件上傳、文件下載、并發(fā)請(qǐng)求等復(fù)雜的操作。在Dart PUB上可以搜索dio。
在項(xiàng)目的pubspec.yaml配置文件里加入引用:
dependencies: dio: ^2.0.14
這樣就可以引用dio的API庫(kù)來(lái)實(shí)現(xiàn)Http網(wǎng)絡(luò)請(qǐng)求了。給一個(gè)完整的dio用法例子:
import 'dart:io'; import 'package:dio/dio.dart'; class DartHttpUtils { //配置dio,通過(guò)BaseOptions Dio _dio = Dio(BaseOptions( baseUrl: "https://abc.com:8090/", connectTimeout: 5000, receiveTimeout: 5000)); //dio的GET請(qǐng)求 getDio() async { var url = "/path1?name=abc&pwd=123"; _dio.get(url).then((Response response) { if (response.statusCode == 200) { print(response.data.toString()); } }); } getUriDio() async { var url = "/path1?name=abc&pwd=123"; _dio.getUri(Uri.parse(url)).then((Response response) { if (response.statusCode == 200) { print(response.data.toString()); } }).catchError((error) { print(error.toString()); }); } //dio的GET請(qǐng)求,通過(guò)queryParameters配置傳遞參數(shù) getParametersDio() async { var url = "/path1"; _dio.get(url, queryParameters: {"name": 'abc', "pwd": 123}).then( (Response response) { if (response.statusCode == 200) { print(response.data.toString()); } }).catchError((error) { print(error.toString()); }); } //發(fā)送POST請(qǐng)求,application/x-www-form-urlencoded postUrlencodedDio() async { var url = "/path2"; _dio .post(url, data: {"name": 'value1', "pwd": 123}, options: Options( contentType: ContentType.parse("application/x-www-form-urlencoded"))) .then((Response response) { if (response.statusCode == 200) { print(response.data.toString()); } }).catchError((error) { print(error.toString()); }); } //發(fā)送POST請(qǐng)求,application/json postJsonDio() async { var url = "/path3"; _dio .post(url, data: {"name": 'value1', "pwd": 123}, options: Options(contentType: ContentType.json)) .then((Response response) { if (response.statusCode == 200) { print(response.data.toString()); } }).catchError((error) { print(error.toString()); }); } // 發(fā)送POST請(qǐng)求,multipart/form-data postFormDataDio() async { var url = "/path4"; FormData _formData = FormData.from({ "name": "value1", "pwd": 123, }); _dio.post(url, data: _formData).then((Response response) { if (response.statusCode == 200) { print(response.data.toString()); } }).catchError((error) { print(error.toString()); }); } // 發(fā)送POST請(qǐng)求,multipart/form-data,上傳文件 postFileDio() async { var url = "/path5"; FormData _formData = FormData.from({ "description": "descriptiondescription", "file": UploadFileInfo(File("./example/upload.txt"), "upload.txt") }); _dio.post(url, data: _formData).then((Response response) { if (response.statusCode == 200) { print(response.data.toString()); } }).catchError((error) { print(error.toString()); }); } //dio下載文件 downloadFileDio() { var urlPath = "https://abc.com:8090/"; var savePath = "./abc.html"; _dio.download(urlPath, savePath).then((Response response) { if (response.statusCode == 200) { print(response.data.toString()); } }).catchError((error) { print(error.toString()); }); } ///其余的HEAD、PUT、DELETE請(qǐng)求用法類似,大同小異,大家可以自己試一下 ///在Widget里請(qǐng)求成功數(shù)據(jù)后,使用setState來(lái)更新內(nèi)容和狀態(tài)即可 ///setState(() { /// ... /// }); }
好了,F(xiàn)lutter的Http網(wǎng)絡(luò)請(qǐng)求詳解就為大家講解到這里。
到此這篇關(guān)于Flutter Http網(wǎng)絡(luò)請(qǐng)求實(shí)現(xiàn)詳解的文章就介紹到這了,更多相關(guān)Flutter Http網(wǎng)絡(luò)請(qǐng)求內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
flutter開發(fā)技巧自定頁(yè)面指示器PageIndicator詳解
這篇文章主要為大家介紹了flutter開發(fā)技巧自定頁(yè)面指示器PageIndicator詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01Android實(shí)現(xiàn)通訊錄效果——獲取手機(jī)號(hào)碼和姓名
這篇文章主要介紹了Android實(shí)現(xiàn)通訊錄效果——獲取手機(jī)號(hào)碼和姓名的相關(guān)資料,需要的朋友可以參考下2016-03-03Android View的事件分發(fā)機(jī)制深入分析講解
事件分發(fā)從手指觸摸屏幕開始,即產(chǎn)生了觸摸信息,被底層系統(tǒng)捕獲后會(huì)傳遞給Android的輸入系統(tǒng)服務(wù)IMS,通過(guò)Binder把消息發(fā)送到activity,activity會(huì)通過(guò)phoneWindow、DecorView最終發(fā)送給ViewGroup。這里就直接分析ViewGroup的事件分發(fā)2023-01-01Android 根據(jù)手勢(shì)頂部View自動(dòng)展示與隱藏效果
這篇文章主要介紹了Android 根據(jù)手勢(shì)頂部View自動(dòng)展示與隱藏效果,本文給大家介紹非常詳細(xì)包括實(shí)現(xiàn)原理和實(shí)例代碼,需要的朋友參考下吧2017-08-08Android PhoneWindowManager監(jiān)聽屏幕右側(cè)向左滑動(dòng)實(shí)現(xiàn)返回功能
這篇文章主要介紹了Android PhoneWindowManager監(jiān)聽屏幕右側(cè)向左滑動(dòng)實(shí)現(xiàn)返回功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04Android實(shí)現(xiàn)帶有記住密碼功能的登陸界面
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)帶有記住密碼功能的登陸界面,主要采用SharedPreferences來(lái)保存用戶數(shù)據(jù),感興趣的小伙伴們可以參考一下2016-05-05Android使用http請(qǐng)求手機(jī)號(hào)碼歸屬地查詢代碼分享
這篇文章主要介紹了Android使用http請(qǐng)求手機(jī)號(hào)碼歸屬地查詢代碼分享的相關(guān)資料,需要的朋友可以參考下2016-06-06android滑動(dòng)解鎖震動(dòng)效果的開啟和取消
在4.0的圓環(huán)滑動(dòng)解鎖中,我們點(diǎn)擊下去的時(shí)候會(huì)有震動(dòng)效果,因?yàn)檫@個(gè)控件設(shè)置的震動(dòng)效果沒有綁定設(shè)置中設(shè)置的觸摸振動(dòng)開關(guān)來(lái)取消振動(dòng)效果,下邊這個(gè)例子實(shí)現(xiàn)了開啟和取消的方法2013-06-06Android編程設(shè)計(jì)模式之責(zé)任鏈模式詳解
這篇文章主要介紹了Android編程設(shè)計(jì)模式之責(zé)任鏈模式,詳細(xì)分析了Android設(shè)計(jì)模式中責(zé)任鏈模式的概念、原理、應(yīng)用場(chǎng)景、使用方法及相關(guān)操作技巧,需要的朋友可以參考下2017-12-12Android實(shí)現(xiàn)自動(dòng)輪播圖效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)自動(dòng)輪播圖效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11