欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Cloud : feign 客户端使用FORM形式POST数据

程序员文章站 2022-07-15 13:02:44
...

本文基于 Spring boot 2.1.2 RELEASE + Spring Cloud Greenwich.RELEASE

feign客户端缺省的参数传递行为

缺省情况下,feign支持GETPOST方式往服务端提交数据,feign客户端的定义也很方便和直观,如下所示 :

@FeignClient(name = "test-service", path = "/test")
public interface TestService {
    @GetMapping(value = "/echo")
    TestModel echoGet(@RequestParam("parameter") String parameter);

    @PostMapping(value = "/echo/post")
    TestModel echoPost(@RequestParam("parameter") String parameter);
}

这种方式的特点是基于基本的注解@GetMapping,@PostMapping,@RequestParam就可以清楚明了地定义出面向服务端API的一个本地方法。

但上述方式中,无论是GET还是POST,所传递的参数都会作为QueryString的一部分出现在URL中。但这种URL传参的方式存在一定的风险:

  1. URL的最大允许长度较小,如果传递的参数数据量比较大,很可能超过此限制,这种情况下程序运行可能会出现错误;
  2. 对于加号+,如果开发人员不做特殊处理,而使用以上缺省feign缺省传参方式,加号会被被错误处理成空格;

错误示例 :

  1. 针对 GET
    DispatcherServlet看到的URL :
GET "/test/echo?parameter=GET%20%3A%20++%20plus%20sign%20contained%2C%20but%20it's%20gone%20unexpectedly."

通过request.getParameterMap()获取到的参数 :

{"parameter":["GET :    plus sign contained, but it's gone unexpectedly."]}
  1. 针对 POST
    DispatcherServlet看到的URL :
POST "/test/echo/post?parameter=POST%20%3A%20++%20plus%20sign%20contained%2C%20but%20it's%20gone%20unexpectedly."

通过request.getParameterMap()获取到的参数 :

{"parameter":["POST :    plus sign contained, but it's gone unexpectedly."]}

feign客户端使用FORM表单形式提交(POST)参数

针对以上URL传参风险的考虑,我们考虑POST FORM方式传递参数来解决这些问题。

1. 提供一个FormEncoder

如果要使用FORM方式提交参数,首先需要确保feign客户端使用的Encoder是一个FormEncoder,因此,我们要提供一个FormEncoderfeign客户端使用。具体通过如**册一个feignFormEncoder bean组件的方式到应用上下文:

@Configuration
public class FeignClientFormPostConfig {
    // 这里会由容器自动注入HttpMessageConverters的对象工厂
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;

    // new一个form编码器,实现支持form表单提交
    // 注意这里方法名称,也就是bean的名称是什么不重要,
    // 重要的是返回类型要是 Encoder 并且实现类必须是 FormEncoder 或者其子类
    @Bean
    public Encoder feignFormEncoder() {
        return new FormEncoder(new SpringEncoder(messageConverters));
    }
}

2. 定义feign客户端方法使用FORM方式提交POST参数

将某个feign客户端方法定义如下 :

   @PostMapping(value = "/echo/post",consumes = {"application/x-www-form-urlencoded"})
    TestModel echoPostForm(Map<String, ?> formParams);

这里有几个要点需要指出 :

  1. 使用注解 @PostMapping 表明要使用 HTTP POST方法;
  2. @PostMapping注解使用属性consumes = {"application/x-www-form-urlencoded"},
  3. 参数使用Map<String, ?>形式 (不再是@RequestParam("parameter")这种形式);

注意 : 这里参数Map<String, ?>key要和服务器端要求的参数名称一致,value的类型要和服务器端要求的类型一致,否则会出现HTTP 400 BAD_REQUEST错误。

使用如此方式,我们就可以通过POST FORM方式传递参数了 , 例子如下 :

针对 POST FORM, 所传递的参数和上面GET/POST例子中类似, 都是一个名为parameter的参数,参数值含有加号 :
DispatcherServlet看到的URL :

POST "/test/echo/post"  

通过request.getParameterMap()获取到的参数 :

{"parameter":["POST FORM : plus sign contained and it's handled correctly."]}

通过这种方式,我们可以看到,加号问题被正确处理,另外基于POST FORM方式通过request body传递参数,我们就不用太担心参数数据量的大小了。

参考资料

SpringCloud Feign Post表单请求
使用Feign实现Form表单提交
Form Encoder

相关标签: Feign