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

本文探讨了在Spring Cloud环境中,Feign客户端如何通过POST FORM方式安全传递参数,避免URL长度限制及加号解析错误等问题,提供了配置FormEncoder及定义feign客户端方法的具体步骤。
部署运行你感兴趣的模型镜像

本文基于 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

您可能感兴趣的与本文相关的镜像

Seed-Coder-8B-Base

Seed-Coder-8B-Base

文本生成
Seed-Coder

Seed-Coder是一个功能强大、透明、参数高效的 8B 级开源代码模型系列,包括基础变体、指导变体和推理变体,由字节团队开源

在Java、Spring Boot和Feign中提交POST请求并传递`form/data`数据,有以下两种常见实现方法: ### 方法一:模拟`multipart/form-data` 若不需要Spring标准的编码,可按如下方式实现。首先定义一个`FeignClient`接口,并在其中添加自定义配置类以使用`SpringFormEncoder`。以下是示例代码: ```java import feign.codec.Encoder; import org.springframework.beans.factory.ObjectFactory; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.support.SpringEncoder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestLine; import feign.form.spring.SpringFormEncoder; import java.io.File; @FeignClient(name = "file-upload-service", configuration = FileUploadServiceClient.MultipartSupportConfig.class) public interface FileUploadServiceClient { @Configuration class MultipartSupportConfig { @Bean public Encoder feignFormEncoder(ObjectFactory<HttpMessageConverters> converters) { return new SpringFormEncoder(new SpringEncoder(converters)); } } // File parameter @RequestLine("POST /send_photo") @RequestHeader("Content-Type: multipart/form-data") void sendPhoto(@Param("is_public") Boolean isPublic, @Param("photo") File photo); // byte[] parameter @RequestLine("POST /send_photo") @RequestHeader("Content-Type: multipart/form-data") void sendPhoto(@Param("is_public") Boolean isPublic, @Param("photo") byte[] photo); // FormData parameter @RequestLine("POST /send_photo") @RequestHeader("Content-Type: multipart/form-data") void sendPhoto(@Param("is_public") Boolean isPublic, @Param("photo") FormData photo); } ``` 在上述代码里,`MultipartSupportConfig`类配置了`SpringFormEncoder`,用于处理`multipart/form-data`类型的请求。同时提供了三种不同参数类型(`File`、`byte[]`、`FormData`)的`sendPhoto`方法,可根据实际需求选用 [^1]。 ### 方法二:通过POST传递FORM格式数据 可以将某个feign客户端方法定义如下: ```java import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import java.util.Map; @Component @FeignClient(value = "http://xx.xx.xxx.xx:xxxx") public interface TestPaperClient { @RequestMapping(value = "/xxx", method = RequestMethod.POST, consumes = {"application/x-www-form-urlencoded"}) TestPaper paperGeneration(Map<String, ?> map); } ``` 这里定义了一个`TestPaperClient`接口,借助`@FeignClient`注解指定服务地址,`paperGeneration`方法使用`@RequestMapping`注解定义了POST请求,并且指定了`consumes`为`application/x-www-form-urlencoded`,以此来传递FORM格式的数据 [^2]。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值