示例
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(...);