• Retrofit源码解析(上)


    简介
    Retrofit是Square公司开发的一款针对Android网络请求的框架,官网地址http://square.github.io/retrofit/ ,在官网上有这样的一句话介绍retrofit,A type-safe HTTP client for Android and Java。我们知道Retrofit底层是基于OKHttp实现的。对okhttp不了解的同学可以看看这一篇文章。okhttp源码解析https://www.cnblogs.com/huangjialin/p/9469373.html


    okhttp简单使用

    build.gradle依赖

    1 implementation 'com.squareup.retrofit2:retrofit:2.4.0'
    2 implementation 'com.squareup.retrofit2:converter-scalars:2.4.0'
    3 implementation ‘com.squareup.retrofit2:converter-gson:2.4.0'

    创建请求接口

     1 /**
     2  * Created by huangjialin on 2018/8/16.
     3  */
     4 
     5 public interface ApiService {
     6 
     7     @GET("api//Client/GetIsOpen")
     8     Call<SwitchTest> getInformation();
     9 
    10 }

    这里以GET请求为例,POST请求后面还会提。接口只是为了测试用,返回什么数据,不要在意。接下来看配置Retrofit

     1 package com.example.huangjialin.retrofittest;
     2 
     3 import android.os.Bundle;
     4 import android.support.v7.app.AppCompatActivity;
     5 import android.util.Log;
     6 import android.view.View;
     7 
     8 import retrofit2.Call;
     9 import retrofit2.Callback;
    10 import retrofit2.Response;
    11 import retrofit2.Retrofit;
    12 import retrofit2.converter.gson.GsonConverterFactory;
    13 import retrofit2.converter.scalars.ScalarsConverterFactory;
    14 
    15 public class MainActivity extends AppCompatActivity {
    16 
    17     @Override
    18     protected void onCreate(Bundle savedInstanceState) {
    19         super.onCreate(savedInstanceState);
    20         setContentView(R.layout.activity_main);
    21         findViewById(R.id.test).setOnClickListener(new View.OnClickListener() {
    22             @Override
    23             public void onClick(View view) {
    24                 testRetrofit();
    25             }
    26         });
    27     }
    28 
    29 
    30     String url = "http://10.31.1.2:93";
    31 
    32     public void testRetrofit() {
    33         //创建retrofit
    34         Retrofit retrofit = new Retrofit.Builder()
    35                 .baseUrl(url) //设置baseURl
    36                 .addConverterFactory(ScalarsConverterFactory.create()) //增加返回值为String的支持
    37                 .addConverterFactory(GsonConverterFactory.create())
    38                 .build();
    39         ApiService apiService = retrofit.create(ApiService.class);
    40         Call<SwitchTest> call = apiService.getInformation();
    41         call.enqueue(new Callback<SwitchTest>() {
    42             @Override
    43             public void onResponse(Call<SwitchTest> call, Response<SwitchTest> response) {
    44                 Log.d("huangjialin", "---onResponse----" + response.body().getMessage());
    45             }
    46 
    47             @Override
    48             public void onFailure(Call<SwitchTest> call, Throwable t) {
    49                 Log.d("huangjialin", "--- 失败----" );
    50             }
    51         });
    52     }
    53 }

    Model类SwitchTest

     1 package com.example.huangjialin.retrofittest;
     2 
     3 /**
     4  * Created by huangjialin on 2018/8/16.
     5  */
     6 
     7 class SwitchTest {
     8     private String Message;
     9     private ModelBean Model;
    10     private int ResultType;
    11 
    12     public String getMessage() {
    13         return Message;
    14     }
    15 
    16     public void setMessage(String message) {
    17         Message = message;
    18     }
    19 
    20     public ModelBean getModel() {
    21         return Model;
    22     }
    23 
    24     public void setModel(ModelBean model) {
    25         Model = model;
    26     }
    27 
    28     public int getResultType() {
    29         return ResultType;
    30     }
    31 
    32     public void setResultType(int resultType) {
    33         ResultType = resultType;
    34     }
    35 
    36     public static class ModelBean {
    37         private boolean Phone;
    38         private boolean Message;
    39         private boolean ClientApp;
    40 
    41         public boolean isPhone() {
    42             return Phone;
    43         }
    44 
    45         public void setPhone(boolean phone) {
    46             Phone = phone;
    47         }
    48 
    49         public boolean isMessage() {
    50             return Message;
    51         }
    52 
    53         public void setMessage(boolean message) {
    54             Message = message;
    55         }
    56 
    57         public boolean isClientApp() {
    58             return ClientApp;
    59         }
    60 
    61         public void setClientApp(boolean clientApp) {
    62             ClientApp = clientApp;
    63         }
    64     }
    65 
    66 }

    最后记得加上网络权限

    1 <uses-permission android:name=“android.permission.INTERNET"/>

    retrofit一个简单的网络请求就可以了……当然,我这里的url是用我司的测试地址,是有网络权限的,所以记得替换成你们自己的地址。使用比较简单,这里不做过多的解释。下面我们看看retrofit的注解

    请求方法

    http请求方式一共有7种,分别是GET,POST、PUT、DELETE、HEAD、OPTIONS、PATCH,而其中我们最常用的就是get和post请求,这里也主要拿这两种方式分析。retrofit设置请求方法主要是通过注解的方式

    get请求

    1 @GET("api//Client/GetIsOpen")
    2  Call<SwitchTest> getInformation();

    post请求

    1 @POST("api/login/GetModel")
    2 Call<LoginModel> login(@Body Login login);

    只需要在每个请求接口上方加上@GET(“aaaa”)或者是@POST(“aaaa”)就可以设置不同请求方式。retrofit除了可以通过注解的方式设置请求方法外,还可以通过注解来设置请求参数。

    GET网络请求注解参数方式

    @Query

    1 @GET("api//Client/GetIsOpen")
    2 Call<SwitchTest> getInformation(@Query("id") String id,@Query("page") int page);

    这种方式会将这些请求参数附加到URL后面,也就是拼接起来。如上面设置的,最后会成为api//Client/GetIsOpen/id/page,当然,如果参数很多,可以使用下面这种方式

    @QueryMap

    1 @GET("api//Client/GetIsOpen")
    2 Call<SwitchTest> getInformation(@QueryMap Map<String,String> parame);

    这种方式可以将参数全部存放到Map中,源码中是这样解释QueryMap的Query parameter keys and values appended to the URL.意思是会将这个key值拼接到url上面。

    除了可以拼接参数以外,还可以动态的拼接URL地址,使用@Path 

    @Path

    源码这样介绍Named replacement in a URL path segment. Values are converted to strings using

    1 @GET("api//Client/{path}")
    2 Call<SwitchTest> pathTest(@Path("path")String path);

    这样我们在调用这个接口的时候,传入的参数就会替换这个path。

    POST网络请求注解参数方式

    我们知道,post请求的参数不是以拼接的形式的,而是将参数放到请求体中的,所以retrofit注解post请求的参数是以另外的方式

    @Body

    源码是这样解释的Use this annotation on a service method param when you want to directly control the request body,意思是当您想要直接控制请求体时,在服务方法参数上使用此注释

    1 @POST("api/login/GetModel")
    2 Call<LoginModel> login(@Body Login login);

    其中Login是一个实体类,上面这个接口api/login/GetModel,是一个登陆接口,登陆就需要账号密码,所以这个实体类就可以这样设置。

     1 package com.example.huangjialin.retrofittest;
     2 
     3 /**
     4  * Created by huangjialin on 2018/8/16.
     5  */
     6 
     7 public class Login {
     8     private String tel;
     9     private String password;
    10 
    11     public Login(String tel, String password) {
    12         this.tel = tel;
    13         this.password = password;
    14     }
    15 }

    当我们调用这个接口时,就可以传入new Login(“账号”,”密码”);

    @Field

    源码是这样解释的:Named pair for a form-encoded request.

    1 @FormUrlEncoded
    2 @POST("api/login/GetModel")
    3 Call<LoginModel> login(@Field("tel") String tel,
    4 @Field("password") String password);

    这里需要注意一个地方使用@Field的时候,一定要记得加上@FormUrlEncoded,这个作用是表示请求主体将使用表单URL编码。

    @FieldMap
    源码是这样解释的:Named key/value pairs for a form-encoded request.翻译就是:表单编码请求的命名键/值对。简单一点的理解就是这样FieldMap可以将参数全部存放到map中。

    1 @FormUrlEncoded
    2 @POST("api/login/GetModel")
    3 Call<LoginModel> login(@FieldMap Map<String,String>parame);

    @Part

    源码是这样解释的:Denotes a single part of a multi-part request.

    1 @Multipart
    2 @POST("user/photo")
    3 Call<实体类> updateUser(@Part MultipartBody.Part photo, @Part("description") RequestBody description);

    其中使用@Part 一定要记得加上@Multipart 源码是这样解释这个的Denotes that the request body is multi-part. Parts should be declared as parameters and annotated with {@link Part @Part}. 表示请求主体是多部分的。部件应该声明为参数和 注释为{@link Part @Part}。当然使用@Part 主要是用来上传文件的,并且是单文件上传的。如果多文件上传的话,可以使用下面这个


    @PartMap

    源码是这样解释的:Denotes name and value parts of a multi-part request.

    1 @Multipart
    2 @POST("user/photo")
    3 Call<实体类> updateUser(@PartMap Map<String, RequestBody> photos,
    4 @Part("description") RequestBody description);

    除了上面这些注解外,我们往往还能看到这个注解

    @Headers

    1 @Headers("Cache-Control: max-age=640000")
    2 @POST("api/login/GetModel")
    3 Call<LoginModel> login(@Body Login login);

    源码的解释和例子是这样的

     1 /**
     2  * Adds headers literally supplied in the {@code value}.
     3  * <pre><code>
     4  * &#64;Headers("Cache-Control: max-age=640000")
     5  * &#64;GET("/")
     6  * ...
     7  *
     8  * &#64;Headers({
     9  *   "X-Foo: Bar",
    10  *   "X-Ping: Pong"
    11  * })
    12  * &#64;GET("/")
    13  * ...
    14  * </code></pre>
    15  * <strong>Note:</strong> Headers do not overwrite each other. All headers with the same name will
    16  * be included in the request.
    17  *
    18  * @see Header
    19  * @see HeaderMap
    20  */

    有什么用的呢??在http请求中,为了防止攻击或是过滤掉不安全的访问或是添加特殊加密的访问等等,用来减轻服务器的压力和保证请求的安全等,就会在请求头上面加一些内容。

    本来,想弄成一篇文章的,但是写完到这里以后,感觉篇幅好长,所以在这里分一下篇幅吧
    Retrofit源码解析(下)https://www.cnblogs.com/huangjialin/p/9492271.html

  • 相关阅读:
    LeetCode0680.验证回文字符串 Ⅱ
    20145208 蔡野 《网络对抗》Exp6 信息搜集与漏洞扫描
    20145208 蔡野 《网络对抗》Exp5 MSF基础应用
    辅助模块:udp_sweep
    对客户端攻击:adobe_toolbutton
    对浏览器攻击:MS10-002
    主动攻击:利用ms08_067_netapi进行攻击
    20145208 蔡野 《网络对抗》Exp4 恶意代码分析
    20145208 蔡野《网络对抗》Exp3 Advanced 恶意代码伪装技术实践
    20145208 蔡野《网络对抗》shellcode注入&Return-to-libc攻击深入
  • 原文地址:https://www.cnblogs.com/huangjialin/p/9492182.html
Copyright © 2020-2023  润新知