利用Feign发post请求遇到的坑

背景

最近转java,背靠公司java大神,利用spring cloud框架重构现有业务,新手遇坑是常事,也是喜闻乐见的,趟坑能让自己快速的学习成长。
Feign是一个声明式的Web服务客户端,使用Feign可使得Web服务客户端的写入更加方便。
具体的介绍就不多说了,直接看github就好,这里写链接内容
这里主要记录一下利用feign发送post请求时遇到的问题。

问题重现

public interface MessageCenterInterface {
    @RequestLine("POST /v3/bbs/BatchAttention")
    @Headers("Content-Type: application/json")
    NetResult batchAttention(BatchAttentionVO batchAttentionVO);
}

// 参数实体
public class BatchAttentionVO {
    private Integer ewtUserId;

    private Integer devicetype;

    private String attentionIds;

    private String attentionTitles;

    public Integer getEwtUserId() {
        return ewtUserId;
    }

    public void setEwtUserId(Integer ewtUserId) {
        this.ewtUserId = ewtUserId;
    }

    public Integer getDevicetype() {
        return devicetype;
    }

    public void setDevicetype(Integer devicetype) {
        this.devicetype = devicetype;
    }

    public String getAttentionIds() {
        return attentionIds;
    }

    public void setAttentionIds(String attentionIds) {
        this.attentionIds = attentionIds;
    }

    public String getAttentionTitles() {
        return attentionTitles;
    }

    public void setAttentionTitles(String attentionTitles) {
        this.attentionTitles = attentionTitles;
    }
}

@Component
@Slf4j
public class HttpManager {

    private MessageCenterInterface messageCenterInterface;

    @Autowired
    private AppConfig appConfig;

    @PostConstruct
    private void initFeign(){
        messageCenterInterface =
                Feign.builder()
                        .encoder(new GsonEncoder())
                        .decoder(new GsonDecoder())
                                .target(MessageCenterInterface.class,"http://messagecenter.233.mistong.com");
    }

    public MessageCenterInterface getMessageCenterInterface() {
        return messageCenterInterface;
    }
}

嗯,很神奇,对方拿不到请求的参数,本以为是封装成实体类BatchAttentionVO不行,看着github上的示例,他是封装成了type-safe类,试了下,也不行,改成string类型,还是不行,有点抓瞎了
这里写图片描述

妈蛋,用PHP自己搭了个服务来调试参数看看。

    public function test(Request $request){
        var_dump($_POST, $_REQUEST);
        //larvel对请求参数的封装,包括所有类型的
        var_dump($request->input());
    }

调试结果

array(0) {
}
array(0) {
}
array(4) {
  ["ewtUserId"]=>
  int(501398)
  ["devicetype"]=>
  int(2)
  ["attentionIds"]=>
  string(11) "39,90,65,97"
  ["attentionTitles"]=>
  string(45) "大课间,充电站,卧谈会,男神女神秀"
}

大爷的,总算知道怎么回事了,肯定是参数传输方式跟服务端没对上,Content-Type改成application/x-www-form-urlencoded试试,结果

array(1) {
  ["{
__"ewtUserId":_501398,
__"devicetype":_2,
__"attentionIds":_"39,90,65,97",
__"attentionTitles":_"大课间,充电站,卧谈会,男神女神秀"
}"]=>
  string(0) ""
}
array(1) {
  ["{
__"ewtUserId":_501398,
__"devicetype":_2,
__"attentionIds":_"39,90,65,97",
__"attentionTitles":_"大课间,充电站,卧谈会,男神女神秀"
}"]=>
  string(0) ""
}
array(1) {
  ["{
__"ewtUserId":_501398,
__"devicetype":_2,
__"attentionIds":_"39,90,65,97",
__"attentionTitles":_"大课间,充电站,卧谈会,男神女神秀"
}"]=>
  string(0) ""
}

还是不太对,参数收到了,但是格式不对

解决办法

自定义encoder类QueryPostMapEncoder,将参数全部拼进body里面去,不采用Content-Type: application/json 参数的形式,顺带还进行了下加密串的拼接

public interface MessageCenterInterface {
    @RequestLine("POST /v3/bbs/BatchAttention")
    NetResult batchAttention(BatchAttentionVO batchAttentionVO);
}

@Component
@Slf4j
public class HttpManager {

    private MessageCenterInterface messageCenterInterface;

    @Autowired
    private AppConfig appConfig;

    @PostConstruct
    private void initFeign(){
        messageCenterInterface =
                Feign.builder()
                        .decoder(new CustomDecoder())
                        .encoder(new QueryPostMapEncoder(appConfig.getMessageCenter().getSignkey()))
                        .logLevel(Logger.Level.FULL)
                        .logger(new Slf4jLogger(MessageCenterInterface.class))
                        .target(MessageCenterInterface.class,appConfig.getMessageCenter().getDomain());
    }

    public MessageCenterInterface getMessageCenterInterface() {
        return messageCenterInterface;
    }
}


public class QueryPostMapEncoder implements Encoder {

    private String secret;

    public QueryPostMapEncoder(String secret) {
        this.secret = secret;
    }

    @Override
    public void encode(Object o, Type type, RequestTemplate requestTemplate) throws EncodeException {
        try {
            Map<String,String> params = ObjectUtils.objectToMapString(o);;
            String sign = SignUtil.sign(params,this.secret);
            requestTemplate.query("sign",sign);

            StringBuilder sb = new StringBuilder();
            sb.append("sign=");
            sb.append(sign);
            for (Map.Entry<String,String> param:params.entrySet()){
                if (param.getValue()!=null) {
                    sb.append("&");
                    sb.append(param.getKey());
                    sb.append("=");
                    sb.append(param.getValue());
                }
            }
            requestTemplate.body(sb.toString());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

调试一下

    array(5) {
  ["sign"]=>
  string(32) "60162f112394550a87675ca8e0b9d061"
  ["attentionIds"]=>
  string(11) "39,90,65,97"
  ["attentionTitles"]=>
  string(45) "大课间,充电站,卧谈会,男神女神秀"
  ["ewtUserId"]=>
  string(6) "501398"
  ["devicetype"]=>
  string(1) "2"
}
array(5) {
  ["sign"]=>
  string(32) "60162f112394550a87675ca8e0b9d061"
  ["attentionIds"]=>
  string(11) "39,90,65,97"
  ["attentionTitles"]=>
  string(45) "大课间,充电站,卧谈会,男神女神秀"
  ["ewtUserId"]=>
  string(6) "501398"
  ["devicetype"]=>
  string(1) "2"
}
array(5) {
  ["sign"]=>
  string(32) "60162f112394550a87675ca8e0b9d061"
  ["attentionIds"]=>
  string(11) "39,90,65,97"
  ["attentionTitles"]=>
  string(45) "大课间,充电站,卧谈会,男神女神秀"
  ["ewtUserId"]=>
  string(6) "501398"
  ["devicetype"]=>
  string(1) "2"
}   

完美解决

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值