Retrofit 如何优雅的请求这样的后台接口? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
maninfog
V2EX    Android

Retrofit 如何优雅的请求这样的后台接口?

  •  
  •   maninfog 2018-08-13 19:19:32 +08:00 13395 次点击
    这是一个创建于 2698 天前的主题,其中的信息可能已经有所发展或是发生改变。

    请求方式:post ;

    请求体为至少包含 token 和 uuid 的 json。eg:{token:"",uuid:"",param1:"",param2:""}. 目前方式,采用继承。

    // 基类 request public class BaseRequest { String token; Sring uuid; public String toJson(){ return new Gson().toJson(this); } } // 子类 public class TestRequest extends BaseRequest { String param1; String param2; } 

    下面是 retrofit 接口。

     @POST fun getXX(@Body requestJson: String) //使用的伪代码 TestRequest testRequest = new TestRequest(); testRequest.param1=""; testRequest.param2=""; String json = testRequest.tojson(); // 网络请求 getXX(json); 

    这种方式缺点很明显,不同的请求接口需要定义不同的请求类去继承,我想要的效果是这样的。

     @POST fun getXX(String param1,String param2) 接口只需要这样写,然后借助一些注解或者 convert 之类的,在真正请求时,会将其转化成上面的格式。 

    还请大佬解惑!!

    30 条回复    2018-08-14 21:25:32 +08:00
    StephenDev
        1
    StephenDev  
       2018-08-13 19:24:52 +08:00 via Android
    你可以试试请求的时候直接扔对象进去,然后将对象转为 map,key 是字段名,value 就是 param,retrofit 支持这样 map 格式
    maninfog
        2
    maninfog  
    OP
       2018-08-13 19:28:40 +08:00
    @StephenDev #1 您应该说的是 @FieldMap 这个注解,但是这个 post 到服务器应该是 param1=""&param2=""这种结构,而不是 json 格式数据,所以应该是不适用的。
    xiangyuecn
        3
    xiangyuecn  
       2018-08-13 19:38:18 +08:00
    发现别人家定义的注解用多了,写代码飞快。。。自己用简单对象搭积木反而不会,哈哈哈哈哈哈。传说:一顿操作猛如虎::一看战绩 0-5 (逃
    MoHen9
        4
    MoHen9  
       2018-08-13 19:41:07 +08:00 via Android
    为什么不把 token 和 uuid 放在 header 中?
    vjnjc
        5
    vjnjc  
       2018-08-13 19:44:40 +08:00 via Android
    没看明白要求。
    按照一楼的思路你用 @body,然后 body 是个 hashmap 不就好了么
    maninfog
        6
    maninfog  
    OP
       2018-08-13 19:56:21 +08:00 via Android
    @MoHen9 后台是这样我也没办法…目前还不能客户端教后台写接口
    maninfog
        7
    maninfog  
    OP
       2018-08-13 19:59:24 +08:00 via Android
    @vjnjc 需求是我用某个注解标记请求参数(比如 @Query @Field 这样的),真正请求时,这些被标记的请求参数会和 token 以及 uuid 一起被序列化成 json 数据作为 body post 到服务器。
    kingme
        8
    kingme  
       2018-08-13 20:06:35 +08:00
    通过拦截器阿,在拦截器里面重新组织
    maninfog
        9
    maninfog  
    OP
       2018-08-13 20:08:48 +08:00 via Android
    @kingme 拦截器只能得到请求头的参数把,对于方法中的参数,拦截器应该取不到阿
    MoHen9
        10
    MoHen9  
       2018-08-13 20:09:00 +08:00 via Android
    @maninfog 楼上正解,可以通过 okhttp 的拦截器动态添加
    pynix
        11
    pynix  
       2018-08-13 20:16:16 +08:00
    认证信息放到 header 中。
    twoyuan
        12
    twoyuan  
       2018-08-13 20:16:50 +08:00
    用 OkHttp 拦截器。通过 chain.request() 取到 request 对象调用 newBuilder() 加上需要的参数后后丢给 chain.process()
    pynix
        13
    pynix  
       2018-08-13 20:19:02 +08:00
    这种调用方式好像也没什么问题,你搞一个构造函数就可以了。

    getXX(new TestRequest(p1,p2));
    maninfog
        14
    maninfog  
    OP
       2018-08-13 20:22:45 +08:00 via Android
    @pynix 这个只是一个方法,一个项目中应该有几十个方法,请求参数都不一样,这样的话就要写几十个这样的类,不够优雅
    maninfog
        15
    maninfog  
    OP
       2018-08-13 20:24:35 +08:00 via Android
    @twoyuan 想过拦截器 但是后台是用的一个整的 json 而不是键值对的形式 所以用拦截器估计不行吧
    twoyuan
        16
    twoyuan  
       2018-08-13 20:30:04 +08:00
    @maninfog #15 可以,在拦截器里取出的 Request Body 就是 JSON,然后追加完参数再构造新的 request 对象就好了
    pynix
        17
    pynix  
       2018-08-13 20:30:28 +08:00
    @maninfog 拦截器应该可以的,不过你从拦截器拿到的 body 可能已经序列化了,你需要反序列化,加入字段再序列化,感觉更坑吧,也有可能不是这样的,我没看过拦截器。
    xiangyuecn
        18
    xiangyuecn  
       2018-08-13 20:49:19 +08:00
    @maninfog #6 这句话真难听,form 表单 application/x-www-form-urlencoded 请求的 body 格式是一个标准格式。。。后端已经吐了一口老血

    顺带杠一句:楼上几位大佬真水( doge
    xiangyuecn
        19
    xiangyuecn  
       2018-08-13 20:54:34 +08:00
    我好像理解错了。。。杠的那句收回来,哈哈


    主题到底是 A:

    后端要求:post: {key1:value,key2:value}
    你发送:post: key1=value&key2=value

    还是 B:

    后端要求:post: key1=value&key2=value
    你发送:post: {key1:value,key2:value}
    maninfog
        20
    maninfog  
    OP
       2018-08-13 20:58:54 +08:00 via Android
    @xiangyuecn 主题是: 后端要求 post json 所以我也得 post json
    maninfog
        21
    maninfog  
    OP
       2018-08-13 21:03:29 +08:00 via Android
    @pynix 的确 即行的话 性能上也有所损耗 要去能在某个接口中拿到方法的参数以及注解就好了
    xiangyuecn
        22
    xiangyuecn  
       2018-08-13 21:16:38 +08:00   1
    杠也杠了,擦一下屁股。虽然没用过 Retrofit,但查了一下,他可以 post 字符串出去,看人家写的:


    这样的话,现在优雅的层面完全就可以不在 Retrofit 这个层面上了,完全在如何优雅的生成一段 json 数据上。
    依我暴力的习惯:

    写一个静态类,类里面两个方法:
    HashMap BuildPostMap()
    String MapToJson(HashMap)

    粗暴的使用:
    1. BuildPostMap:生成一个 map,map 里面已包含所有必要参数数据
    2. ........ 根据不同接口 put 参数到 map,至于参数从哪里来.....(这不重要)
    3. MapToJson:map 转成 json,这么通用的功能,估计这个方法都可以省略
    719465553
        23
    719465553  
       2018-08-13 21:21:54 +08:00
    @POST
    fun getXX(@Body request: Request)
    pynix
        24
    pynix  
       2018-08-13 21:24:24 +08:00
    @maninfog 如果后端是本公司的,应该可以尝试更正吧,认证信息一般放 header,body 放数据。。。。
    maninfog
        25
    maninfog  
    OP
       2018-08-13 21:27:23 +08:00 via Android
    @xiangyuecn 还是感谢你 提供了这种暴力的思路……缺陷在于参数和接口有点分离 …我将继续探寻是否有更好的做法
    kassadin
        26
    kassadin  
       2018-08-14 03:35:52 +08:00
    @maninfog #7 这个思路就行,用 @query, 然后参数都在 url 上,post body 为空。

    手动在 interceptor 中把参数取出来存 map 转 json 并去掉,map 添加通用参数 token, uid, 然后 map 转 requestBody 就行了

    需要注意的就是 query 会有同名 a=1&a=2,尽量规避同名参数就可以了。
    maninfog
        27
    maninfog  
    OP
       2018-08-14 08:41:15 +08:00 via Android
    @kassadin Retrofit 好像 post 方法不支持 @Query,会报错,所以应该只能用到 @Field,用这个的话不知道拦截器中能获取到不,一会儿我去试试吧。
    yescpu
        28
    yescpu  
       2018-08-14 10:02:20 +08:00
    Retrofit+OKHttp 可以很优雅的处理这个问题:

    class CommonInterceptor implements Interceptor{
    Map<String, String> mCommonParams;

    public Response intercept(Chain chain) throws IOException {

    if(get){
    request = addCommonParamsToUrl(request);
    }else if(post){
    RequestBody requestBody = request.body();
    if(formType){
    addCommonparamsToForm(requestBody);
    }else if(jsonType){
    addCommonParamsToJson(requestBody);
    }
    ...
    if (requestBody != null) {
    Request.Builder requestBuilder = request.newBuilder();
    request = requestBuilder
    .post(requestBody)
    .build();
    }
    }
    reture request;
    }
    }
    kassadin
        29
    kassadin  
       2018-08-14 14:34:46 +08:00
    @maninfog @query 是拼接 url 的,肯定可以。 @Field 用的是 StringConverter,合不出来 json。 @Body 只支持一个参数,只解析一次,自定义 converter 也实现不了多个具名参数拼 json。
    snowflake007
        30
    snowflake007  
       2018-08-14 21:25:32 +08:00
    没太看懂,token uuid ,不用每个请求接口都定义吧,拦截器插入到 Header 不是很好。
    https://www.jianshu.com/p/04ce0c91e3ee
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2538 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 14:33 PVG 22:33 LAX 06:33 JFK 09:33
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86