gpt4 book ai didi

SpringCloud OpenFeign Post请求400错误解决方案

转载 作者:qq735679552 更新时间:2022-09-27 22:32:09 26 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章SpringCloud OpenFeign Post请求400错误解决方案由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

在微服务开发中SpringCloud全家桶集成了OpenFeign用于服务调用,SpringCloud的OpenFeign使用SpringMVCContract来解析OpenFeign的接口定义。 但是SpringMVCContract的Post接口解析实现有个巨坑,就是如果使用的是@RequestParam传参的Post请求,参数是直接挂在URL上的.

问题发现与分析 。

最近线上服务器突然经常性出现CPU高负载的预警,经过排查发现日志出来了大量的OpenFeign跨服务调用出现400的错误(HTTP Status 400).

一般有两种情况:

  • nginx 返回400
  • java应用返回400

通过分析发现400是java应用返回的,那么可以确定是OpenFeign客户端发起跨服务请求时出现异常了。 但是查看源码发现出现这个问题的服务接口非常简单,就是一个只有三个参数的POST请求接口,这个错误并不是必现的错误,而是当参数值比较长(String)的时候才会出现。 所以可以初步确认可能是参数太长导致请求400,对于POST请求因参数太长导致400错误非常疑惑,POST请求除非把参数挂在URL上,否则不应该出现400才对.

问题排查 。

为了验证上面的猜测,手写了一个简单的示例,在验证过程中特意开启了OpenFeign的debug日志.

首先编写服务接口 。

这是一个简单的Post接口,仅有一个参数(这里的代码仅用于验证,非正式代码) 。

?
1
2
3
4
5
@FeignClient (name = "user-service-provider" )
public interface HelloService {
   @PostMapping ( "/hello" )
   public String hello( @RequestParam ( "name" ) String name);
}

编写服务 。

服务这里随便写一个Http接口即可(同上,代码仅用于验证) 。

?
1
2
3
4
5
6
7
8
9
10
11
12
@SpringBootApplication
@RestController
public class Starter {
   @RequestMapping ( "/hello" )
   public String hello(String name) {
     return "User服务返回值:Hello " + String.valueOf(name);
   }
    
   public static void main(String[] args) {
     SpringApplication.run(Starter. class , args);
   }
}

服务注册并调用 。

将服务注册到注册中心上,通过调用hello服务 。

?
1
2
3
4
5
6
@Autowired
public HelloService helloService;  
@RequestMapping ( "/hello" )
public String hello(String name) {
   return helloService.hello(name);
}

通过日志可以发现,SpringCloud集成OpenFeign的POST请求确实是直接将参数挂在URL上,如下图:

SpringCloud OpenFeign Post请求400错误解决方案

正是因为这个巨坑,导致了线上服务器经常性高CPU负载预警.

问题解决 。

问题知道了,那么就好解决了,用SpringCloud官方的说法是可以使用@RequestBody来解决这个问题,但是@RequestBody的使用是有限制的,也就是参数只能有一个,而且需要整个调用链路都做相应的调整,这个代价有点高,这里不采用这种方式,而是采用RequestInterceptor来处理.

编写RequestInterceptor 。

这里将request的queryLine取下来放在body中,需要注意的是,只有body没有值的时候才能这么做.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public class PostRequestInterceptor implements RequestInterceptor {
   @Override
   public void apply(RequestTemplate template) {
     if ( "post" .equalsIgnoreCase(template.method()) && template.body() == null ) {
       String query = template.queryLine();
       template.queries( new HashMap<>());
       if (StringUtils.hasText(query) && query.startsWith( "?" )) {
         template.body(query.substring( 1 ));
       }
       template.header( "Content-Type" , "application/x-www-form-urlencoded;charset=UTF-8" );
     }
   }
}

配置RequestInterceptor 。

feign: client: config: default: requestInterceptors: cn.com.ava.yaolin.springcloud.demo.PostRequestInterceptor 。

在下图可以看出请求参数不再挂在URL上了 。

SpringCloud OpenFeign Post请求400错误解决方案

@RequestBody的解决方案 。

问题虽然解决了,但采用的不是官方推荐的方案,这里将官方推荐的这种@RequestBody的解决方法也贴出来。 使用@RequestBody解决,需要4个步骤:

编写请求参数Bean 。

?
1
2
3
4
5
6
7
8
9
public class HelloReqForm {
   private String name;
   public String getName() {
     return name;
   }
   public void setName(String name) {
     this .name = name;
   }
}

调整接口声明 。

@PostMapping("/hello") public String hello(@RequestBody HelloReqForm form),

调整服务调用 。

HelloReqForm form = new HelloReqForm(); form.setName(name); return helloService.hello(form),

调整服务实现 。

@RequestMapping("/hello") public String hello(@RequestBody HelloReqForm form) { } 。

最终调用日志 。

SpringCloud OpenFeign Post请求400错误解决方案

涉及的Java类 。

最后列出一些涉及的java类:

  • SpringMVCContract 服务接口
  • RequestParamParameterProcessor 参数
  • feign.RequestTemplate Rest请求构造器
  • feign.Request 处理http请求

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.

原文链接:http://www.manongjc.com/detail/19-fxjynmrashzgysy.html 。

最后此篇关于SpringCloud OpenFeign Post请求400错误解决方案的文章就讲到这里了,如果你想了解更多关于SpringCloud OpenFeign Post请求400错误解决方案的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com