写在前面: 本文是我看到Retrofit官方推荐的一个Retrofit技术文档,感觉收益匪浅,特此想把文档翻译一下,大家一起学习。
原文地址:https://futurestud.io/tutorials/retrofit-getting-started-and-android-client
这是关于Rtrofit系列文章的第二篇。他解释了如何应用retrofit来进行身份校验。
在上一篇文章中,我们创建了发送API/HTTP请求的Android客户端。我将以此为基础来实现基础的校验功能。
当然,你可以再次阅读上篇文章才获得更多的信息。
集成基础验证
让我们来更新ServiceGenerator类,并给它添加一个请求验证的功能。下面这段代码是实现这个的一个例子。
我们可以在Retroift1.9的代码的基础上实现Retrofit2.0的代码。如果你只使用第二次正式发布版本的retrofit,那么就跳过这个,看第二部分即可。
Retrofit 1.9
public class ServiceGenerator {
public static final String API_BASE_URL = "https://your.api-base.url";
private static RestAdapter.Builder builder = new RestAdapter.Builder()
.setEndpoint(API_BASE_URL)
.setClient(new OkClient(new OkHttpClient()));
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null, null);
}
public static <S> S createService(Class<S> serviceClass, String username, String password) {
if (username != null && password != null) {
// concatenate username and password with colon for authentication
String credentials = username + ":" + password;
// create Base64 encodet string
final String basic =
"Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
builder.setRequestInterceptor(new RequestInterceptor() {
@Override
public void intercept(RequestFacade request) {
request.addHeader("Authorization", basic);
request.addHeader("Accept", "application/json");
}
});
}
RestAdapter adapter = builder.build();
return adapter.create(serviceClass);
}
}
Retrofit 2
public class ServiceGenerator {
public static final String API_BASE_URL = "https://your.api-base.url";
private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
private static Retrofit.Builder builder =
new Retrofit.Builder()
.baseUrl(API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create());
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass, null, null);
}
public static <S> S createService(Class<S> serviceClass, String username, String password) {
if (username != null && password != null) {
String credentials = username + ":" + password;
final String basic =
"Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);
httpClient.addInterceptor(new Interceptor() {
@Override
public Response intercept(Interceptor.Chain chain) throws IOException {
Request original = chain.request();
Request.Builder requestBuilder = original.newBuilder()
.header("Authorization", basic)
.header("Accept", "application/json")
.method(original.method(), original.body());
Request request = requestBuilder.build();
return chain.proceed(request);
}
});
}
OkHttpClient client = httpClient.build();
Retrofit retrofit = builder.client(client).build();
return retrofit.create(serviceClass);
}
}
第二个方法有两个参数:username 和password。你也可以将username 参数替换为email。
这个创建客户端的基础方法和第一个方法一样,使用RestAdapter类来为了HTTP请求和响应创建OkHttp客户端。
区别在于:我们使用RequestInterceptor来为通过OkHttp客户端执行的HTTP请求设置检验头信息。
但是这只在username和password被提供的时候。如果你没有通过这个方法来传入username和password,它就会和第一个方法那样创建一个相同的客户端,这就是为什么我们能从ServiceGenerator类中简化了第一个方法。
几乎所有的webservice和API都会评估HTTP请求的验证头信息。这就是为什么我们将已编译的资格信息放置于头部。
为防止你将要调用的客户端的webservice解析其他的头部信息来期望获取用户资格,协调你的头部信息和验证。
如果你想要以一种特定的格式获得服务器反馈的话,那么所获得的头部是很重要的。
在我们的例子中,我们希望能获得返回的JSON格式的响应,因为Retroift自动应用google的GSON来序列化对象。
使用方法
只需要调用ServiceGenerator的类中的新方法就可以了。例如下面代码所示:
Retrofit 2
public interface LoginService {
@POST("/login")
Call<User> basicLogin();
}
这个接口只有一个方法:basicLogin。它有User类作为响应值,并不期望其他的查询和路径参数。
现在你可以通过传送那你的给定的身份信息来创建HTTP客户端。
Retrofit2
LoginService loginService =
ServiceGenerator.createService(LoginService.class, "user", "secretpassword");
Call<User> call = loginService.basicLogin();
call.enqueue(new Callback<User >() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
if (response.isSuccessful()) {
// user object available
} else {
// error response, no access to resource?
}
}
@Override
public void onFailure(Call<User> call, Throwable t) {
// something went completely south (like no internet connection)
Log.d("Error", t.getMessage());
}
}
ServiceGenerator方法会产生一个HTTP客户端,其中包含已定义的验证头部。一旦你调用了loginService的basicLogin方法,提供的身份信息将能自动传送到API端口。