Retrofit是目前主流网络框架之一,往往结合OKHttp一起使用。Retrofit提供网络请求接口,OKhttp专门负责请求网络,因为现在项目主流框架是RxJava+Okhttp+Retrofit,所以我将Retrofit的讲解放在了Rx系列专题。
(1)依赖
//OKHttp依赖
implementation 'com.squareup.okhttp3:okhttp:3.12.2'
//Retrofit依赖
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
//GSON依赖
implementation 'com.google.code.gson:gson:2.8.5'
//GSON转换器依赖
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
依赖这边有个坑,retrofit的版本要和converter的版本保持一致,否则Json和对象之间的转换可能会报错。
(2)一般用法
- 声明接口
public interface SearchFileAPIService {
@FormUrlEncoded
@POST("file/search?from=upload")
Call<ResponseBody> fileSearch(@Field("filetype") String filetype, @Field("filename") String filename);
}
-
请求实现
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://xxxxxx:82/oa/").build(); SearchFileAPIService searchFileAPIService = retrofit.create(SearchFileAPIService.class); Call<ResponseBody> call = searchFileAPIService.fileSearch("-1", "1"); call.enqueue(new Callback<ResponseBody>() { @Override public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) { if(response != null && response.isSuccessful()){ try { Log.d("aaa", response.body().string()); } catch (IOException e) { e.printStackTrace(); } } } @Override public void onFailure(Call call, Throwable t) { Log.d("aaa", t.getMessage()); } });
我们先来看一下retrofit的基本代码,以上代码正是retrofit的post请求。
之所以在文章一开头就贴出基本代码是因为需要说明以下几点:
(1)
本文重点介绍Retrofit,与RxJava结合使用将在下节介绍;
(2)
retrofit用于接口的封装,结合OKHttp可以优雅的实现网络请求框架;
(3)
retrofit第一步总是声明接口,以上代码声明了SearchFileAPIService接口,我们可以在SearchFileAPIService声明多个方法,以上代码只封装了fileSearch方法,retrofit提供了多种注解,@FormUrlEncoded
、@POST
、@Field
都是retrofit的注解,当然还有其它注解,文章后面会讲解;
(4)
baseUrl有两种,一种不带路径,比如:http://xxxxxx:82
,另一种带路径,比如: http://xxxxxx:82/oa/
,这里需要重点注意:不带路径的baseUrl结尾可以不带有'/',但是带路径的baseUrl接口必须以'/'结尾,否则会报错,如图:
(5)
Call后面必须添加泛型,否则会报错,泛型类型不允许是String
、Integer
或者其他基本数据类型,这里用将ResponseBody
作为泛型类型即可,ResponseBody
是OKHttp中的类,所以Retrofit有时候需要结合OKHttp使用。
其实需要注意的不止是以上5点,还有很多需要注意的地方,如果过早的指出那就更加不能理解了。
以上声明的5点只是打一个预防针,文章后面会重新说明。
(3)Retrofit的请求方式注解
- GET请求注解:
@GET
GET请求是请求方式的其中一种,下面我来封装一个最简单的GET请求接口
public interface SearchFileAPIService {
@GET("/")
Call<ResponseBody> getBaidu();
}
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://www.baidu.com")
.build();
SearchFileAPIService searchFileAPIService = retrofit.create(SearchFileAPIService.class);
Call<ResponseBody> call = searchFileAPIService.getBaidu();
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response != null && response.isSuccessful()){
try {
Log.d("aaa", "onResponse:"+response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("aaa", "onFailure:"+t.getMessage());
}
});
请求结果如下:
- POST请求注解:
@POST
POST请求是请求方式的一种,POST请求上面已经给出例子了。
- HTTP请求:
@HTTP
@HTTP
可以使用任何请求,现在就以GET请求为例
public interface SearchFileAPIService {
@HTTP(method = "GET", path = "user_user", hasBody = false)
Call<ResponseBody> getBaidu3();
}
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://www.baidu.com")
.build();
SearchFileAPIService searchFileAPIService = retrofit.create(SearchFileAPIService.class);
Call<ResponseBody> call = searchFileAPIService.getBaidu3();
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response != null && response.isSuccessful()){
try {
Log.d("aaa", "onResponse:"+response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("aaa", "onFailure:"+t.getMessage());
}
});
以上代码请求网络需要跳过证书(怎么跳过证书文章后面会讲到)
请求头报文和上面一样:
- DELETE请求注解:
@DELETE
DELETE请求相对GET和POST请求而言用的比较少
public interface SearchFileAPIService {
@HTTP(method = "DELETE", path = "delete", hasBody = true)
Call<ResponseBody> deleteSomething();
}
或者
public interface SearchFileAPIService {
@DELETE("/{delete}")
Call<ResponseBody> deleteSomething(@Path("delete") String delete);
}
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://www.baidu.com")
.build();
SearchFileAPIService searchFileAPIService = retrofit.create(SearchFileAPIService.class);
Call<ResponseBody> call = searchFileAPIService.deleteSomething("delete_delete");
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response != null && response.isSuccessful()){
try {
Log.d("aaa", "onResponse:"+response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}else{
Log.d("aaa", "onResponse:"+response.message());
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("aaa", "onFailure:"+t.getMessage());
}
});
以上代码请求网络需要跳过证书(怎么跳过证书文章后面会讲到)
目前当前接口调试是不通的,大家也不要纠结为什么没用了,到目前为止我也没用过这个请求,以后用到的话可以补充。不过查询资料之后得到一句解释:
DELETE请求顾名思义,就是执行相应的删除操作,配合数据库进行相应的删除动作。
- PUT请求:
@PUT
用于更新资源
- PATCH请求:
@PATCH
该请求是对put请求的补充,用于更新局部资源
- OPTIONS请求:
@OPTIONS
(以后补充)
- head请求:
@HEAD
(以后补充)
(4)Retrofit的请求参数注解
- url 替换:
@Path
我们就基于以上请求百度页面的例子添加@Path
,代码如下:
public interface SearchFileAPIService {
@GET("/{user}")
Call<ResponseBody> getBaidu2(@Path("user") String user);
}
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://www.baidu.com")
.build();
SearchFileAPIService searchFileAPIService = retrofit.create(SearchFileAPIService.class);
Call<ResponseBody> call = searchFileAPIService.getBaidu2("user_user");
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response != null && response.isSuccessful()){
try {
Log.d("aaa", "onResponse:"+response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("aaa", "onFailure:"+t.getMessage());
}
});
以上代码请求网络需要跳过证书(怎么跳过证书文章后面会讲到)
请求头如下:
通过以上代码演示,@Path
的作用已经显而易见了,@GET("/{user}")
中的user是一个参数,参数变量用{}
修饰。
- 表单字段:
@Filed
和@FiledMap
@Filed
和@FiledMap
主要用于POST请求表单数据的声明,我们来看一下接口的定义
public interface SearchFileAPIService {
@FormUrlEncoded
@POST("file/search?from=upload")
Call<ResponseBody> fileSearch(@Field("filetype") String filetype, @Field("filename") String filename);
@FormUrlEncoded
@POST("file/search?from=upload")
Call<ResponseBody> fileSearch2(@FieldMap Map<String, String> map)
}
下面贴一下完整的使用
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://xxxxxxxx:82/oa/").build();
SearchFileAPIService searchFileAPIService = retrofit.create(SearchFileAPIService.class);
Call<ResponseBody> call = searchFileAPIService.fileSearch("-1", "1");
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response != null && response.isSuccessful()){
try {
Log.d("aaa", response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call call, Throwable t) {
Log.d("aaa", t.getMessage());
}
});
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http:/xxxxxxxxx:82/oa/").build();
SearchFileAPIService searchFileAPIService = retrofit.create(SearchFileAPIService.class);
Map<String, String> map = new HashMap();
map.put("filetype", "-1");
map.put("filename", "1");
Call<ResponseBody> call = searchFileAPIService.fileSearch2(map);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response != null && response.isSuccessful()){
try {
Log.d("aaa", response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call call, Throwable t) {
Log.d("aaa", t.getMessage());
}
});
- POST请求非表单数据:
@Body
在post请求时,我们可以传递键值对,也可以传递键值对的map集合,使用@Body
我们可以传递一个对象,利用json转换器将对象转成json,代码如下:
public interface SearchFileAPIService {
@POST("file/search?from=upload")
Call<ResponseBody> fileSearch3(@Body FileBean fileBean);
}
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.baseUrl("http://xxxxxxxxxx:82/oa/").build();
SearchFileAPIService searchFileAPIService = retrofit.create(SearchFileAPIService.class);
FileBean fileBean = new FileBean();
fileBean.setFiletype("-1");
fileBean.setFilename("1");
Call<ResponseBody> call = searchFileAPIService.fileSearch3(fileBean);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response != null && response.isSuccessful()){
try {
Log.d("aaa", response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call call, Throwable t) {
Log.d("aaa", t.getMessage());
}
});
这里使用了addConverterFactory
,这是添加转换器,文章后面会讲到。
- 指定请求路径:
@Url
一般情况下,请求路径是在@POST
的参数中声明的,一旦使用@Url
来指定请求路径,@POST
就不能传递传输。代码如下:
public interface SearchFileAPIService {
@POST()
Call<ResponseBody> fileSearch4(@Url String url, @Body FileBean fileBean);
}
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.baseUrl("http://xin-ikea.cn:82/oa/").build();
SearchFileAPIService searchFileAPIService = retrofit.create(SearchFileAPIService.class);
FileBean fileBean = new FileBean();
fileBean.setFiletype("-1");
fileBean.setFilename("1");
Call<ResponseBody> call = searchFileAPIService.fileSearch4("file/search?from=upload", fileBean);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response != null && response.isSuccessful()){
try {
Log.d("aaa", response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call call, Throwable t) {
Log.d("aaa", t.getMessage());
}
});
- Get中指定参数:
@Query
和@QueryMap
我定义了一个接口
@FormUrlEncoded
@POST("file/search?from=upload")
Call<ResponseBody> fileSearch5(@Query("filetype") String filetype, @Query("filename") String filename, @Field("filetype") String filetype1, @Field("filename") String filename1);
抓到的报文如下:
我们发现在原本URL的基础上拼接了filetype和filename两个参数,所以 @Query
和 @QueryMap
其实主要用于GET请求。接口如下:
@GET("/")
Call<ResponseBody> getJianshu1(@Query("name") String name, @Query("age") int age);
@GET("/")
Call<ResponseBody> getJianshu2(@QueryMap Map<String, String> map);
-
@Part
和@PartMap
@Part
:用于表单字段,Part和PartMap与Multipart注解结合使用,适合文件上传的情况
@PartMap
:用于表单字段,默认接受的类型是Map<String,REquestBody>,可用于实现多文件上传
这两种注解将在文章下面和Multipart注解一起讲解。
(5)Retrofit响应格式注解
- Form表单数据:
@FormUrlEncoded
@FormUrlEncoded
和@Field
或@FieldMap
一起配合使用,用于POST请求传递表单数据。
public interface SearchFileAPIService {
@FormUrlEncoded
@POST("file/search?from=upload")
Call<ResponseBody> fileSearch(@Field("filetype") String filetype, @Field("filename") String filename);
@FormUrlEncoded
@POST("file/search?from=upload")
Call<ResponseBody> fileSearch2(@FieldMap Map<String, String> map);
}
- 发送multipart数据:
@Multipart
一般和@Part
或@PartMap
一起配合使用,支持单文件上传,多文件上传,也支持表单和文件一起上传。
代码如下:
public interface SearchFileAPIService {
@Multipart
@POST("FileUpload/FileUploadServlet")
Call<ResponseBody> uploadFlie2(@Part MultipartBody.Part file);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://192.168.0.105:8080").build();
SearchFileAPIService searchFileAPIService = retrofit.create(SearchFileAPIService.class);
File file = new File(Environment.getExternalStorageDirectory() + File.separator + "iam.jpg");
// 创建 RequestBody
//application/otcet-stream
RequestBody requestFile = RequestBody.create(MediaType.parse("application/otcet-stream"), file);
//新建Part
MultipartBody.Part body = MultipartBody.Part.createFormData("photo1", file.getName(), requestFile);
// 添加描述
String descriptionString = "hello, 这是文件描述";
RequestBody description = RequestBody.create(MediaType.parse("multipart/form-data"), descriptionString);
Call<ResponseBody> call = searchFileAPIService.uploadFlie2(body);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response != null && response.isSuccessful()){
try {
Log.d("aaa", response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call call, Throwable t) {
Log.d("aaa", t.getMessage());
}
});
我们查看一下报文:
- 响应用字节流的形式返回:
@Streaming
该注解可以用于下载文件。
代码如下:
public interface SearchFileAPIService {
@Streaming
@GET("/1.apk")
Call<ResponseBody> downloadFile();
}
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://192.168.0.105:8080").build();
SearchFileAPIService searchFileAPIService = retrofit.create(SearchFileAPIService.class);
Call<ResponseBody> call = searchFileAPIService.downloadFile();
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response != null && response.isSuccessful()){
boolean writtenToDisk = writeResponseBodyToDisk(response.body());
Log.d("aaa", "下载成功:"+writtenToDisk);
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("aaa", "下载失败");
}
});
//写入到磁盘根目录
private boolean writeResponseBodyToDisk(ResponseBody body) {
try {
File futureStudioIconFile = new File(Environment.getExternalStorageDirectory() + File.separator + "myapk.apk");
InputStream inputStream = null;
OutputStream outputStream = null;
try {
byte[] fileReader = new byte[4096];
final long fileSize = body.contentLength();
long fileSizeDownloaded = 0;
inputStream = body.byteStream();
outputStream = new FileOutputStream(futureStudioIconFile);
while (true) {
int read = inputStream.read(fileReader);
if (read == -1) {
break;
}
outputStream.write(fileReader, 0, read);
fileSizeDownloaded += read;
final long finalFileSizeDownloaded = fileSizeDownloaded;
runOnUiThread(new Runnable() {
@Override
public void run() {
bt_1.setText("file download: " + finalFileSizeDownloaded + " of " + fileSize);
}
});
}
outputStream.flush();
return true;
} catch (IOException e) {
return false;
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
} catch (IOException e) {
return false;
}
}
报文如下:
(6)Retrofit的请求头注解
@Headers
用于添加固定请求头,可以同时添加多个。通过该注解添加的请求头不会相互覆盖,而是共同存在。
@Headers({"User-Agent:okhttp/3.14.1","User-Agent:okhttp/3.14.2","Content-Type: text/html"})
@GET("/")
Call<ResponseBody> getJianshu2();
请求报文如下:
@Header
作为方法的参数传入,用于添加不固定值的Header,该注解会更新已有的请求头
@GET("/")
Call<ResponseBody> getJianshu2(@Header("Content-Type") String contentType);
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://www.jianshu.com").build();
SearchFileAPIService searchFileAPIService = retrofit.create(SearchFileAPIService.class);
Call<ResponseBody> call = searchFileAPIService.getJianshu2("text/html");
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response != null && response.isSuccessful()){
Log.d("aaa", "11111111111111111");
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("aaa", "2222222222222222");
}
});
报文如下:
(7)怎么跳出SSL证书校验?
有时候,我们想要请求https开头的链接,有些服务器会做限制,不让别人访问自己的服务器,这个时候我们需要跳出证书校验了,Retrofit的client方法可以重新封装OkHttpClient,使hostnameVerifier返回true即可跳过证书校验。
就以访问“https://www.jianshu.com”为例,代码如下:
public class SslClient {
private SslClient(){}
static class SingleHolder{
public static SslClient instance = new SslClient();
}
public static SslClient getInstance(){
return SingleHolder.instance;
}
public OkHttpClient getOkHttpClient(){
OkHttpClient.Builder builder = new OkHttpClient.Builder();
X509TrustManager x509TrustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
TrustManager[] trustManager = new TrustManager[]{
x509TrustManager
};
try {
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManager, new SecureRandom());
SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
builder.sslSocketFactory(sslSocketFactory,x509TrustManager);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return hostname.contains("www.jianshu.com");
}
});
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return builder.build();
}
}
public interface SearchFileAPIService {
@GET("/")
Call<ResponseBody> getJianshu();
}
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://www.jianshu.com")
.client(SslClient.getInstance().getOkHttpClient())
.build();
SearchFileAPIService searchFileAPIService = retrofit.create(SearchFileAPIService.class);
Call<ResponseBody> call = searchFileAPIService.getJianshu();
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response != null && response.isSuccessful()){
try {
Log.d("aaa", "onResponse:"+response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}else{
Log.d("aaa", "onResponse:"+response.message());
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Log.d("aaa", "onFailure:"+t.getMessage());
}
});
(8)转换器
我们先来搜索一下有多少转换器依赖吧
这里就以gson转换器为例,其它转换器不做讲解。
一般情况下,我们的post请求代码是这样写的
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://123.124.175.239:7001").build();
SearchFileAPIService searchFileAPIService = retrofit.create(SearchFileAPIService.class);
Call<ResponseBody> call = searchFileAPIService.getCarList("868256021322879", "862679", "c907d5df8b26550eaf2841ed9bcf51bb44b9ae1b", "d3974829a20747579c90e2004a5ed1c5");
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response != null && response.isSuccessful()){
try {
Log.d("aaa", response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
当我们获取返回结果时,发现返回结果时一个json或者json数组
,这个时候我们可以利用转换器将json直接转成对象,改造之后的代码如下:
public interface SearchFileAPIService {
@FormUrlEncoded
@POST("/xxx/interface/carList")
Call<ArrayList<Car>> getCarList(@Field("IMEI") String IMEI, @Field("appid") String appid, @Field("appkey") String appkey, @Field("userId") String userId);
}
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://123.124.175.239:7001")
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.build();
SearchFileAPIService searchFileAPIService = retrofit.create(SearchFileAPIService.class);
Call<ArrayList<Car>> call = searchFileAPIService.getCarList("868256021322879", "862679", "c907d5df8b26550eaf2841ed9bcf51bb44b9ae1b", "d3974829a20747579c90e2004a5ed1c5");
call.enqueue(new Callback<ArrayList<Car>>() {
@Override
public void onResponse(Call<ArrayList<Car>> call, Response<ArrayList<Car>> response) {
if(response != null && response.isSuccessful()){
ArrayList<Car> carlist = response.body();
for(Car car : carlist){
Log.d("aaa", car.getCarNumber());
}
}
}
@Override
public void onFailure(Call<ArrayList<Car>> call, Throwable t) {
}
});
获取的结果是一个数组:
(9)日志拦截器
当我们网络请求时,要想看到报文,有时候必须依赖于抓包工具,本人常用的抓包工具是Fiddler
,除了抓包工具之外,OkHttp提供了日志拦截器,可以打印报文日志。
通过下图代码,可以添加拦截求
创建日志拦截器有两种方式:
- 自定义的方式
/**
* 创建日志拦截器
*
* @return
*/
public class LogInterceptor implements Interceptor {
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
Log.d("bbb", "请求数据:");
Log.d("bbb", "请求URL:"+String.valueOf(request.url()));
Log.d("bbb", "请求头:"+String.valueOf(request.headers()));
Log.d("bbb", "请求体:"+request.toString());
okhttp3.Response response = chain.proceed(request);
Log.d("bbb", "响应数据:");
Log.d("bbb", "返回码:"+String.valueOf(response.code()));
Log.d("bbb", "响应头:"+String.valueOf(response.headers()));
Log.d("bbb", "响应体:"+String.valueOf(response.body().string()));
return response;
}
}
打印日志如下:
- 使用日志拦截器依赖
implementation 'com.squareup.okhttp3:logging-interceptor:3.5.0'
/**
* 创建日志拦截器
*
* @return
*/
public static HttpLoggingInterceptor getHttpLoggingInterceptor() {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(
new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
Log.e("bbb", "log = " + message);
}
});
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return loggingInterceptor;
}
捕获到的日志如下:
(10)自定义CookieJar
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(getHttpLoggingInterceptor())
.cookieJar(new CookieJar() {
final HashMap<HttpUrl, List<Cookie>> cookieStore = new HashMap<>();
@Override
public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
cookieStore.put(url, cookies);//保存cookie
//也可以使用SP保存
}
@Override
public List<Cookie> loadForRequest(HttpUrl url) {
List<Cookie> cookies = cookieStore.get(url);//取出cookie
return cookies != null ? cookies : new ArrayList<Cookie>();
}
})
.build();
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://123.124.175.239:7001")
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.client(client)
.build();
(11)取消请求
call.cancel();