Flutter Http: http原生网络请求
1.json和String相互转换
Map userInfo = {
"username":"张三",
"age":20
}
json.decode(result.body); //json字符串(String) 转换为map
json.encode(userInfo); // map类型转换为String
2.http库
依赖: http: ^0.12.2
GitHub:https://github.com/dart-lang/http
安装:flutter packages get
导入:import 'package:http/http.dart' as http;
常用方法
get(dynamic url, { Map<String, String> headers }) → Future<Response>
(必须)url:请求地址
(可选)headers:请求头
post(dynamic url, { Map<String, String> headers, dynamic body, Encoding encoding }) → Future<Response>
(必须)url:请求地址
(可选)headers:请求头
(可选)body:参数
(编码)Encoding:编码 默认UTF-8
例子
3.自定义头信息
class UserAgentClient extends http.BaseClient {
final String userAgent;
final http.Client _inner;
UserAgentClient(this.userAgent, this._inner);
Future<http.StreamedResponse> send(http.BaseRequest request) {
request.headers['user-agent'] = userAgent;
return _inner.send(request);
}
}
4.get请求
_getData() async {
var apiUrl = "http://a.itying.com/api/productlist";
final http.Response result = await http.get(apiUrl); //
if (result.statusCode == 200) {
print(result.body);
setState(() {
/*
{
"result": [{
"_id": "5ac0896ca880f20358495508",
"title": "精选热菜",
"pid": "0",
}, {
"_id": "5ac089e4a880f20358495509",
"title": "特色菜",
"pid": "0",
}
]
}
*/
this._list = json.decode(result.body)["result"];
});
} else {
print("失败${result.statusCode}");
}
}
返回信息:返回 http.Response
5.Post请求
1.普通Post请求,默认x-www-form-urlencoded ,和get请求区别不大
_postData() async {
var apiUrl = "http://192.168.0.5:3000/dologin";
var result = await http.post(apiUrl, body: {'username': '张三', 'age': '20'});
if (result.statusCode == 200) {
print(json.decode(result.body));
} else {
print(result.statusCode);
}
}
2.Body请求,要设置ContentType.json
//发送POST请求,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');
});
}
3.MultipartRequest请求,默认是form-data
// 发送POST请求,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');
});
}
4.上传文件
// 发送POST请求,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);
});
});
}
解释一下MultipartRequest:MultipartRequest.send()返回的是StreamedResponse,和普通的Response还不一样
在MultipartRequest中,fields是一个Map;files是一个MultipartFile的List:
final Map<String, String> fields;
final List<MultipartFile> _files;
List<MultipartFile> get files => _files;
fields里存储的key-value就是body中的文本字段,key是name,value是内容。files里存储的就是需要上传的文件,MultipartFile有两个命名构造方法和一个静态方法:
factory MultipartFile.fromBytes(String field, List<int> value, {String filename, MediaType contentType})
factory MultipartFile.fromString(String field, String value, {String filename, MediaType contentType})
static Future<MultipartFile> fromPath(String field, String filePath, {String filename, MediaType contentType})
最后调用MultipartRequest中的send方法会将fields和files中的内容按照格式生成body,然后发送POST请求。
需要注意的是request.send()返回的是StreamedResponse,和普通的Response还不一样,需要用如下方法才能读取内容:
var respStr = await response.stream.transform(utf8.decoder).join();
LogUtil.i("upload response is $respStr");
6.Flutter请求抓包问题修复
Flutter请求抓包问题
一般做HTTP请求都会想要抓包来看一下请求的格式和内容对不对,但是这次连上代理以后发现其他请求都能抓到,只有Flutter里的请求抓不到…
上网搜索了一下,发现已经有人遇到过这个问题,并给出了解决方案,具体的分析这里就不再贴了,详情请看Flutter中http请求抓包解决方案。这里只写一下结论,增加如下代码就可以抓包了,"http_proxy"填代理PC的IP和端口即可。
var httpClient = new HttpClient();
httpClient.findProxy = (url) {
return HttpClient.findProxyFromEnvironment(url, environment: {"http_proxy": 'http://192.168.124.7:8888',});
};
但是有一个问题,我们用的是http插件,不是原生的HttpClient,这又应该怎么设置呢?
遇事不决读源码,在http中的client.dart里,我看到这样的注释:
/// Creates a new client.
///
/// Currently this will create an `IOClient` if `dart:io` is available and
/// a `BrowserClient` if `dart:html` is available, otherwise it will throw
/// an unsupported error.
意思是如果有dart:io,就会创建一个IOClient;如果有dart:html,就会创建一个BrowserClient。HttpClient正是dart:io中的一员,所以我们来看看IOClient的实现:
/// The underlying `dart:io` HTTP client.
HttpClient _inner;
/// Creates a new HTTP client.
IOClient([HttpClient inner]) : _inner = inner ?? new HttpClient();
这就很清晰了,IOClient实际就是HttpClient的封装,那我们只要自己创建一个HttpClient设置好代理后再创建IOClient就可以了,所以我们完整的上传代码就是:
static Future<bool> upload(BaseUploadData data) async {
var request = await data.getRequest();
HttpClient httpClient = new HttpClient();
httpClient.findProxy = (url) {
return HttpClient.findProxyFromEnvironment(url, environment: {"http_proxy": 'http://10.45.109.70:8088',});
};
IOClient client = IOClient(httpClient);
var response = await client.send(request);
var respStr = await response.stream.transform(utf8.decoder).join();
LogUtil.i("upload response is $respStr");
return response.statusCode == 200;
}