示例
Http请求从请求方法上可以分为两大类,我们把它们称为Url类请求(UrlRequest)和Body类请求(BodyRequest),因为一类只可以是简单的url
,而另一类不仅仅可以是简单的url
,也可以使用流来发送自定义RequestBody
。
Url类的请求方法:
GET, HEAD, OPTIONS, TRACE
Body类的请求方法:
POST, PUT, DELETE, PATCH
在示例中,Url类的请求我们以GET
为代表,Body类的请求我们以POST
为代表。
对Callback的说明
这里我们先以GET
请求方法为例,我们请求一个UserInfo
,先写一个完整的请求。。
Kalle.get("http://www.example.com")
.perform(new Callback<UserInfo, String>() {
@Override
public void onStart() {
// 请求开始了,可以显示个dialog。
}
@Override
public void onResponse(SimpleResponse<UserInfo, String> response) {
// 请求响应了。
if(response.isSucceed()) {
// 业务成功,拿到业务成功的数据。
UserInfo user = response.succeed();
...
} else {
// 业务失败,拿到业务失败的数据。
String message = response.failed();
...
}
...
}
@Override
public void onException(Exception e) {
// 请求发生异常了。
}
@Override
public void onCancel() {
// 请求被取消了。
}
@Override
public void onEnd() {
// 请求结束了,可以关闭之前显示的dialog。
}
});
一些特点:
- 回调了
onStart()
,就肯定会回调onEnd()
。 - 回调了
onStart()
,也可能会回调onCancel()
,接着一定会回调onEnd()
。 - 没有回调
onStart()
时,也可能会回调onCancel()
,接着一定会回调onEnd()
。 onException()
是客户端环境发生异常时回调,比如超时、网络错误、发送数据失败。onResponse()
只要服务器有响应就会回调,不论响应码是100、200、300、400、500段中的任何一个。
Kalle中用Callback
来回调请求的响应结果,Callback
需要两个泛型,第一个泛型表示业务成功时的数据类型,第二个泛型表示业务失败时的数据类型。最终会交给转换器把数据转为开发者指定类型的数据。上述代码中,先抛开onException(Exception)
不管,在onResponse(SimpleResponse)
中我们希望业务成功时直接拿到UserInfo
对象示例,业务失败时返回错误原因。
简化Callback
Kalle中提供了一个SimpleCallback
,它是Callback
的直接子类,且限定了错误时返回的数据时String
,使用它写一个请求就很简单了:
Kalle.get("http://www.example.com")
.perform(new SimpleCallback<UserInfo>() {
@Override
public void onResponse(SimpleResponse<UserInfo, String> response) {
// 请求响应了。
if(response.isSucceed()) {
UserInfo user = response.succeed();
...
} else {
Toast.show(response.failed());
}
}
});
在上述代码中,我们只传了一个泛型UserInfo
就可以请求到UserInfo
的实体了,对于业务判断也仅仅需要一个isSucceed()
方法即可(不用判断http响应码、业务数据的响应码、数据结构是否符合预期等),当然这个简单的写法并不是臆测的,而是需要我们使用Converter
做一些业务封装,请参考业务封装。
如果开发者需要处理onException()
和onCancel()
等情况,还需要再重写这几个方法,但是经过业务封装后这几个方法也不需要写了。另外有些业务场景在业务失败时返回的不是一句提示,也就是说不是String
,而是另一个对象示例,此时开发者可以参考SimpleCallback
写一个自己的Callback
类。
Url中的PATH
很多开发者的url
中的path
段会带有需要encode
的字符(例如中文),在Kalle中开发者不需要关注自己的path
中是否带有需要encode
的字符,例如这样的url
是完全没问题的:
http://www.example.com/示例/演示.apk
值得一提的是,Kalle中支持开发者拼接path
,例如有些按照RESTFUL风格设计的服务器接口,如果我们要读取用户信息可能是这样:
http://www.example.com/{userId}/info
这样的情况并不少见,在Kalle中我们可以这样写:
String userId = ...;
Kalle.get("http://www.example.com")
.path(userId)
.path("info")
.perform(new SimpleCallback<UserInfo>() {
@Override
public void onResponse(SimpleResponse<UserInfo, String> response) {
// 请求响应了。
UserInfo = response.result();
}
});
简单的GET请求
Kalle.get("http://www.example.com")
.header("version", 123) // 添加请求头。
.setHeader("name", "kalle") // 设置请求头,会覆盖默认头和之前添加的头。
.param("name", "kalle") // 添加请求参数。
.perform(...);
这里还有一些其它属性可以设置,比如超时时间,代理服务器,SSL证书,域名信任器等等,开发者可以自行探索。
另外值得注意的是,这里添加的参数最终会拼接到url
上发送,因为GET
请求属于我们之前说过的Url类请求,这样的行为是Http协议规定的。
简单的POST请求
Kalle.post("http://www.example.com")
.header("version", 123) // 添加请求头。
.setHeader("name", "kalle") // 设置请求头,会覆盖默认头和之前添加的头。
.param("name", "kalle") // 添加请求参数。
.perform(...);
其它的通用设置跟GET
请求是一样的,这里不再赘述。
Body类型请求添加参数的两种情况
我们知道Body类型的请求既可以通过RequestBody
发送参数,也可以通过url
发送参数(以何种方式发送参数取决与服务端与客户端的约定),Kalle同时支持这两种方式。
例如服务端给一个接口:http://www.example.com/user?id={userId}&name={username}
,需要我们使用POST
方法请求,并且需要在RequestBody
中发送age
和sex
的参数,那么我们可以这样做:
String userId = ...;
String userName = ...;
int userAge = ...;
int userSex = ...;
Kalle.post("http://www.example.com/user")
.urlParam("id", userId)
.urlParam("name", userName)
.param("age", userAge)
.param("sex", userSex)
.perform(...);
服务端的另一个接口:http://www.example.com/user?id={userId}
,需要我们使用POST
方法请求,并且需要在RequestBody
中push
一段json:
String json = ...;
Kalle.post("http://www.example.com/user")
.urlParam("id", userId)
.body(new JsonBody(json))
.perform(...);
更多关于RequestBody
的使用请继续往下看。
表单提交文件
表单上传文件是Http中上传文件最常见的一种,几乎90%的上传文件都以form方式上传的。在Kalle中,在Body类型的请求中,只要添加了File
或者Binary
参数,会自动以表单的形式发送请求,写法有如下几种:
第一种:
File file = ...;
Kalle.post("http://www.example.com")
.file("header", file)
.perform(...);
第二种:
File file = ...;
Binary binary = new FileBinary(file);
Kalle.post("http://www.example.com")
.binary("header", binary)
.perform(...);
这样就把一个文件作为名为header
的参数的值,以form的形式提交服务器了。
你也可以为header
参数提交多个文件(前提是你们服务端支持或者需要),这里有几种方式:
第一种,为一个key
添加多次File
:
File file1 = ...;
File file2 = ...;
Kalle.post("http://www.example.com")
.file("header", file1)
.file("header", file2)
.perform(...);
第二种,添加List<File>
:
List<File> fileList = ...;
Kalle.post("http://www.example.com")
.files("header", fileList)
.perform(...);
第三种,为一个key
添加多次Binary
:
Binary binary1 = ...;
Binary binary2 = ...;
Kalle.post("http://www.example.com")
.binary("header", binary1)
.binary("header", binary2)
.perform(...);
第四种,添加List<Binary>
:
List<Binary> binaries = ...;
Kalle.post("http://www.example.com")
.binary("header", binaries)
.perform(...);
提交自定义Body
只要是Body类型的请求都可以提交自定义RequestBody
,这是一个示例:
RequestBody body = ...;
Kalle.post("http://www.example.com")
.body(body)
.perform(...);
我们看到的RequestBody
是一个接口,在Kalle中已经提供了几种默认实现:
FileBody // 用Body发送文件。
StringBody // 用Body发送字符串。
JsonBody // 用Body发送Json字符串。
XmlBody // 用Body发送Xml字符串。
FormBody // 用Body模拟发送表单。
UriBody // 用Body发送Url参数。
例如用RequestBody
发送一个文件:
File file = ...;
RequestBody body = new FileBody(file);
Kalle.post("http://www.example.com")
.body(body)
.perform(...);
例如用RequestBody
发送一段字符串:
RequestBody body = new StringBody("I like you.");
Kalle.post("http://www.example.com")
.body(body)
.perform(...);
发送Json
和Xml
的同发送String
一样:
String json = ...;
RequestBody body = new JsonBody(json);
Kalle.post("http://www.example.com")
.body(body)
.perform(...);
String xml = ...;
RequestBody body = new XmlBody(xml);
Kalle.post("http://www.example.com")
.body(body)
.perform(...);
UrlBody
是在Body类型的请求没有添加File
和Binary
时内部自动转换使用的,一般开发者不会使用到,如果开发者想用也是可以的:
UrlBody body = UrlBody.newBuilder()
.param("name", "Kalle")
.param("age", 18)
.param("sex", 1)
.build();
Kalle.post("http://www.example.com")
.body(body)
.perform(...);
FormBody
是在需要以表单实行发送参数时使用的。前面有说到过,Body类型的请求,只要添加了File
或者Binary
就会自动转化为表单的形式提交也是使用的FormBody
。要特别说明的是,有些开发者需要在没有文件的时候也使用表达发送参数,那么我们可以这样做:
File file = ...;
FormBody body = FormBody.newBuilder()
.param("name", "Kalle")
.param("age", 18)
.param("sex", 1)
.file("header", file)
.build();
Kalle.post("http://www.example.com")
.body(body)
.perform(...);