首先我们需要找写测试的url链接,有一个好地方,那就是Github提供了很多api 但在此之前我们需要先行处理一些事,比如注册Github账号,获取一个token 下面的Github账号是我专门为Flutter准备的,token值就不加密了,大家不要乱玩。
小头像-->Settings-->Developer settings -->Personal access tokens-->Generate new token
api:https://api.github.com/repos/用户名/项目名/contents/文件路径?access_token=token值 请求头:Content-Type=application/json,请求体如下,注意文件内容需要用base64 可以用wanandroid里的工具转化,该请求的其他参数可以详见Github的相应api
{
"message": "commit from toly ",//提交信息
"content": "aGVsbG8="//数据内容
}
复制代码
Flutter中发送put请求,在github项目中添加一个文件
import 'package:http/http.dart' as client;
main() {
put();
}
void put() {
var baseUrl="https://api.github.com/";
var operate="repos/toly-flutter/flutter_journey/contents/";
var path="http-put-file.txt";
var params="?access_token=4514388836f6da9f6c6cf7ba0721f2a6d1e89528";//请求参数
var api =baseUrl+operate+path+params;//url
Map<String ,String> headers = {"Content-Type":"application/json"};//请求头
var reqBody="""
{
"message": "commit from commit from toly",
"content": "aGVsbG8="
}
""";//请求体
client.put(api,headers:headers,body: reqBody).then((rep){
print(rep.statusCode);
print(rep.body);
});
}
复制代码
注,Dart中将字符串转换base64可以:base64Encode(utf8.encode("hello"));
1.3:通过put请求修改一个github文件
api:https://api.github.com/repos/用户名/项目名/contents/文件路径?access_token=token值 请求头:Content-Type=application/json,请求体如下,注意文件内容需要用base64 关于sha值,在添加的时候,响应体中有,见上图。每次修改也会返回新的sha值
{
"message": "update by toly ",//提交信息
"content": "aGVsbG8="//数据内容
"sha":"文件所对应的sha值"
}
复制代码
- Flutter中发送put请求,在github项目中修改一个文件
void update() {
var baseUrl="https://api.github.com/";
var operate="repos/toly-flutter/flutter_journey/contents/";
var path="http-put-file.txt";
var params="?access_token=4514388836f6da9f6c6cf7ba0721f2a6d1e89528";//请求参数
var api =baseUrl+operate+path+params;//url
Map<String ,String> headers = {"Content-Type":"application/json"};//请求头
var reqBody="""
{
"message": "update by toly",
"content": "5byg6aOO5o2354m554OI",
"sha":"b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0"
}
""";//请求体
client.put(api,headers:headers,body: reqBody).then((rep){
print(rep.statusCode);
print(rep.body);
});
}
复制代码
1.4:通过delete请求删除一个github文件
api:https://api.github.com/repos/用户名/项目名/contents/文件路径?access_token=token值 请求头:Content-Type=application/json,可以要当前文件的sha值
{
"message": "delete by toly ",//提交信息
"sha":"文件所对应的sha值"
}
复制代码
http库的delete请求居然不能加请求体?!这里用PostMan演示一下
1.5:用post提交一个issue
api:https://api.github.com/repos/用户名/项目名/issues?access_token=token值 请求头:Content-Type=application/json,可以要当前文件的sha值
{
"title": "一起来Flutter之旅吧",
"body": "Flutter,大家感觉怎么样?应该不难吧!"
}
复制代码
- Flutter中发送post请求,在github项目中添加一条issue
void post() {
var baseUrl="https://api.github.com/";
var operate="repos/toly-flutter/flutter_journey/issues";
var params="?access_token=4514388836f6da9f6c6cf7ba0721f2a6d1e89528";//请求参数
var api =baseUrl+operate+params;//url
Map<String ,String> headers = {"Content-Type":"application/json"};//请求头
var reqBody="""
{
"title": "一起来Flutter之旅吧",
"body": "Flutter,大家感觉怎么样?应该不难吧!"
}
""";//请求体
client.post(api,headers:headers,body: reqBody).then((rep){
print(rep.statusCode);
print(rep.body);
});
}
复制代码
1.6:使用get请求获取一个issue
api:https://api.github.com/repos/用户名/项目名/issues/第几个?access_token=token值
void get(){
//GET /repos/:owner/:repo/issues/:issue_number
var baseUrl="https://api.github.com/";
var operate="repos/toly-flutter/flutter_journey/issues/1";
var params="?access_token=4514388836f6da9f6c6cf7ba0721f2a6d1e89528";//请求参数
var api =baseUrl+operate+params;//url
client.get(api).then((rep){
print(rep.statusCode);
print(rep.body);
});
}
复制代码
好了,Http的几种常用的请求方式基本都会了吧。
2. Json的解析
2.0:简介
Dart中的Map<String,String>对象和Json非常相似,所以可以用其作为转换媒介 通过convert包中的json.decode方法,可以将Json字符串转化成一个Map对象 在实体类中可以根据这个Map对象的属性对实体类进行实例化。
import 'dart:convert';
main() {
String jsonStr = """
{
"name":"Flutter之旅",
"author":"张风捷特烈"
}
""";
var book = Book.fromMap(json.decode(jsonStr));
print(book.name);//Flutter之旅
print(book.author);//张风捷特烈
}
class Book {
String name;
String author;
Book.fromMap(Map<String, dynamic> json) {//根据Map穿件实例
name = json["name"];
author = json["author"];
}
}
复制代码
2.1: 获取json
Github的https://api.github.com/users/用户名可以获取用户基本信息 这里就先解析我的https://api.github.com/users/toly1994328吧
{
"login": "toly1994328",
"id": 26687012,
"node_id": "MDQ6VXNlcjI2Njg3MDEy",
"avatar_url": "https://avatars3.githubusercontent.com/u/26687012?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/toly1994328",
"html_url": "https://github.com/toly1994328",
"followers_url": "https://api.github.com/users/toly1994328/followers",
"following_url": "https://api.github.com/users/toly1994328/following{/other_user}",
"gists_url": "https://api.github.com/users/toly1994328/gists{/gist_id}",
"starred_url": "https://api.github.com/users/toly1994328/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/toly1994328/subscriptions",
"organizations_url": "https://api.github.com/users/toly1994328/orgs",
"repos_url": "https://api.github.com/users/toly1994328/repos",
"events_url": "https://api.github.com/users/toly1994328/events{/privacy}",
"received_events_url": "https://api.github.com/users/toly1994328/received_events",
"type": "User",
"site_admin": false,
"name": "张风捷特烈(toly)",
"company": "捷特王国",
"blog": "http://www.toly1994.com",
"location": "China",
"email": null,
"hireable": null,
"bio": "The king of coder.",
"public_repos": 64,
"public_gists": 0,
"followers": 238,
"following": 9,
"created_at": "2017-03-26T09:55:25Z",
"updated_at": "2019-07-15T08:05:52Z"
}
复制代码
2.2:实体类的生成
你也可以一点一点写出这个实体类,不过推荐用生成的方法,比较有时候字段太多,比较费劲 这里给一个用起来还不错的地方JSON to Dart,有时间自己写个转换插件来玩玩
class User {
String login;
int id;
String nodeId;
String avatarUrl;
String gravatarId;
String url;
String htmlUrl;
String followersUrl;
String followingUrl;
String gistsUrl;
String starredUrl;
String subscriptionsUrl;
String organizationsUrl;
String reposUrl;
String eventsUrl;
String receivedEventsUrl;
String type;
bool siteAdmin;
String name;
String company;
String blog;
String location;
String email;
String hireable;
String bio;
int publicRepos;
int publicGists;
int followers;
int following;
String createdAt;
String updatedAt;
User.fromJson(Map<String, dynamic> json) {
login = json['login'];
id = json['id'];
nodeId = json['node_id'];
avatarUrl = json['avatar_url'];
gravatarId = json['gravatar_id'];
url = json['url'];
htmlUrl = json['html_url'];
followersUrl = json['followers_url'];
followingUrl = json['following_url'];
gistsUrl = json['gists_url'];
starredUrl = json['starred_url'];
subscriptionsUrl = json['subscriptions_url'];
organizationsUrl = json['organizations_url'];
reposUrl = json['repos_url'];
eventsUrl = json['events_url'];
receivedEventsUrl = json['received_events_url'];
type = json['type'];
siteAdmin = json['site_admin'];
name = json['name'];
company = json['company'];
blog = json['blog'];
location = json['location'];
email = json['email'];
hireable = json['hireable'];
bio = json['bio'];
publicRepos = json['public_repos'];
publicGists = json['public_gists'];
followers = json['followers'];
following = json['following'];
createdAt = json['created_at'];
updatedAt = json['updated_at'];
}
复制代码
2.3.网络请求+json的使用
现在完全可以将以前写的界面改一改,然后用Github获取的数据填充进去 这里只是简单展示一下,说明网络数据和布局界面的对接,并没有做得太精细 GithubPanel就是以前写得界面稍微改装一下,这里代码就不贴了。
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as client;
import 'day6/github_panel.dart';
import 'day6/user.dart';
void main() {
var baseUrl = "https://api.github.com/";
var operate = "users/";
var name = "toly1994328";
var api = baseUrl + operate + name; //url
client.get(api).then((rep) {
var user = User.fromJson(json.decode(rep.body));
print(user.avatarUrl);
var scaffold = Scaffold(
appBar: AppBar(title: Text("Flutter之旅"),),
body: GithubPanel(user: user,)
);
var app = MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: scaffold,
);
return runApp(app);
});
}
复制代码
2.4.组件的再封装
你会发现上面虽然能用,但是看着真的非常难受,怎么让它用起来爽一点呢,两个字封装 实现一个GithubUserPanel,用法是传入一个用户名参数就行了。并且复用以前的面板。 由于网络访问是异步的,我们需要一个有状态的组件,当异步加载完成之后,再setState重新渲染。
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as client;
import 'github_panel.dart';
import 'user.dart';
class GithubUserPanel extends StatefulWidget {
GithubUserPanel({
Key key,
this.userName,
}) : super(key: key);
final String userName;
@override
_GithubUserPanelState createState() => _GithubUserPanelState();
}
class _GithubUserPanelState extends State<GithubUserPanel> {
var baseUrl = "https://api.github.com/";
var operate = "users/";
var panel;
@override
void initState() {
super.initState();
var api = baseUrl + operate + widget.userName; //url
client.get(api).then((rep) {
var user = User.fromJson(json.decode(rep.body));
panel = GithubPanel(
user: user,
);
setState(() {});
});
}
@override
Widget build(BuildContext context) {
return Container(
child: panel,
);
}
}
复制代码
也就这写代码就行了,是不是感受到了GithubPanel复用的爽感。
2.5.使用
这样用起来就和往常一样,只要传个名字就行了
void main() {
var scaffold = Scaffold(
appBar: AppBar(title: Text("Flutter之旅"),),
body: GithubUserPanel(userName: "toly1994328",)
);
var app = MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: scaffold,
);
return runApp(app);
}
复制代码
3.网络请求包dio的使用
dio作为JoJo的奇妙冒险的几部大boss,听名字就挺霸气,在网页搜dio根本没有Flutter的事 上来说的那个http包相对比较原始,dio封装的更好些,用法比较多。 反正再怎么玩,都脱离不了http请求,所以要分清主次,切莫舍本逐末。
dependencies:
dio: ^2.1.13
复制代码
3.1:get获取github用户信息
var dio=Dio();
var baseUrl = "https://api.github.com/";
var operate = "users/";
var api=baseUrl+operate+"toly1994328";
dio.get(api).then((rep)=>print(rep.data));
复制代码
3.2: put请求添加github项目文件
void put() {
var baseUrl="https://api.github.com/";
var operate="repos/toly-flutter/flutter_journey/contents/";
var path="http-put-file-dio.txt";
var params="?access_token=4514388836f6da9f6c6cf7ba0721f2a6d1e89528";//请求参数
var api =baseUrl+operate+path+params;//url
Map<String ,String> headers = {"Content-Type":"application/json"};//请求头
var reqBody="""
{
"message": "commit from commit from toly",
"content": "aGVsbG8="
}
""";//请求体
Dio().put(api,queryParameters:headers,data: reqBody).then((rep){
print(rep.statusCode);
print(rep.data);
});
}
复制代码
3.3:delete请求删除github项目文件
dio中的delete是可以添加请求体的
void delete() {
var baseUrl="https://api.github.com/";
var operate="repos/toly-flutter/flutter_journey/contents/";
var path="http-put-file-dio.txt";
var params="?access_token=4514388836f6da9f6c6cf7ba0721f2a6d1e89528";//请求参数
var api =baseUrl+operate+path+params;//url
Map<String ,String> headers = {"Content-Type":"application/json"};
var reqBody="""
{
"message": "delete by toly",
"sha": "b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0"
}
""";
Dio().delete(api,queryParameters:headers,data: reqBody).then((rep){
print(rep.data);
});
}
复制代码
3.4:post提交一条issue
void post() {
var baseUrl="https://api.github.com/";
var operate="repos/toly-flutter/flutter_journey/issues";
var params="?access_token=4514388836f6da9f6c6cf7ba0721f2a6d1e89528";//请求参数
var api =baseUrl+operate+params;//url
Map<String ,String> headers = {"Content-Type":"application/json"};//请求头
var reqBody="""
{
"title": "张风捷特烈",
"body": "我是谁,我在哪里,我要到哪去?"
}
""";//请求体
Dio().post(api,queryParameters:headers,data: reqBody).then((rep){
print(rep.statusCode);
print(rep.data);
});
}
复制代码
3.5:通过dio下载
就拿掘金的app下载吧,在dio中是很方便的,一行搞定。
var url="";
Dio().download(url,"./掘金.apk").then((rep){
print(rep.statusCode);
print(rep.data);
});
复制代码
3.6:通过dio上传
文件上传一直是个较难问题,要实现文件上传,你需要一点后端的知识 核心就是客户端将数据通过请求给服务器,服务器将请求中的内容进行操作 上传也就是服务器将数据或文件存储到了服务端指定位置。 一般通过表单提交,也可以直接将二进制流通过请求体给服务端。
FormData formData = FormData.from({//创建表单
"name": "toly",
"age": 25,
"data": UploadFileInfo(File("./data.json"), "data.json"),
"image": UploadFileInfo(File("./photo.png"), "photo.png"),
});
var api="/loadFile";
Dio().post(api, data: formData).then((rep){//将表单通过请求体传给服务端
});
复制代码
3.7:基本配置参数
看Dio的源码中有一个可选参数BaseOptions
---->[dio-2.1.13/lib/src/dio.dart:53]----
class Dio {
/// Create Dio instance with default [Options].
/// It's mostly just one Dio instance in your application.
Dio([BaseOptions options]) {
---->[dio-2.1.13/lib/src/options.dart:39]----
class BaseOptions extends _RequestConfig {
BaseOptions({
String method,//请求方法
int connectTimeout,//链接超时
int receiveTimeout,//接收超时
Iterable<Cookie> cookies,//cookies
this.baseUrl,//基础Url
this.queryParameters,//请求参数
Map<String, dynamic> extra,
Map<String, dynamic> headers,//请求头
ResponseType responseType = ResponseType.json,//返回类型
ContentType contentType,//内容类型
ValidateStatus validateStatus,
bool receiveDataWhenStatusError = true,
bool followRedirects = true,
int maxRedirects = 5,
RequestEncoder requestEncoder,
ResponseDecoder responseDecoder,
}) : super(
复制代码
关于更多dio的用法,这里不过多介绍,可以去这里看一下,dio作者的讲解