Spring boot中feign使用GET/POST请求方式及@RequestParam,@RequestBody,@RequestPart的区别
使用@RequestPart,@RequestBody后 ,feign会使用post请求来访问远程客户端,并设置content-type为application/json,然后将@RequestPart/@RequestBody标识的参数以json格式放在body中,客户端接收需要使用@RequestBody进行接收,@RequestPart对应的 content-type为multipart/form-data或multipart/mixed stream
使用@RequestParam,无论是post还是get请求,@RequestParam标识的参数都会已queryString形式拼接在url后面,content-type为null,客户端接收需要使用@RequestParam进行接收
feign请求示例
@RequestMapping(value = "/get_requestParam",method = RequestMethod.GET)
Object get_requestParam(@RequestParam("accountId")String accountId);
@RequestMapping(value = "/get_requestPart",method = RequestMethod.GET)
Object get_requestPart(@RequestPart("accountId")String accountId);
@RequestMapping(value = "/get_requestBody",method = RequestMethod.GET)
Object get_requestBody(@RequestBody QueryAvailableTrialVoucherByUserParam param);
@RequestMapping(value = "/post_requestParam",method = RequestMethod.POST)
Object post_requestParam(@RequestParam("accountId") String accountId);
@RequestMapping(value = "/post_requestPart",method = RequestMethod.POST)
Object post_requestPart(@RequestPart("accountId") String accountId);
@RequestMapping(value = "/post_requestBody",method = RequestMethod.POST)
Object post_requestBody(@RequestBody QueryAvailableTrialVoucherByUserParam param);
客户端接口示例
@GetMapping("/get_requestParam")
public Object get_requestParam(@RequestParam("accountId") String accountId) {
return "get_requestParam";
}
//requestPart 方式为post请求并需要使用@RequestBody接收
@PostMapping("/get_requestPart")
public Object get_requestPart(@RequestBody String accountId) {
return "get_requestPart";
}
@PostMapping("/get_requestBody")
public Object get_requestBody(@RequestBody QueryAvailableTrialVoucherByUserParam param) {
return "get_requestBody";
}
@PostMapping("/post_requestParam")
public Object post_requestParam(@RequestParam("accountId") String accountId) {
return "post_requestParam";
}
//requestPart 需要使用@RequestBody接收
@PostMapping("/post_requestPart")
public Object post_requestPart(@RequestBody String accountId) {
return "post_requestPart";
}
@PostMapping("/post_requestBody")
public Object post_requestBody(@RequestBody QueryAvailableTrialVoucherByUserParam param) {
return "post_requestBody";
}
可能导致的问题
使用@RequestParam 发请求出现url长度过长问题
原因
无论是post还是get请求,@RequestParam标识的参数都会已queryString形式拼接在url后面,但是服务器对接收的url是有长度限制的,会截断后面的参数,致使请求失败
解决方法
- 修改
yml或properties配置文件server: port: 4450 # 增加服务器请求头接受大小,URL 就是头部的一部分 max-http-header-size: 10485760 - 把@RequestParam 的参数全部封装成一个对象,用@RequestBody 方式对该对象进行请求
使用@RequestBody 发请求出现 400 error Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t)
原因
传输的请求体body过大,开启了gzip压缩来传输请求,提升效率,而客户端content-type为 application/json,使用JSON的格式接受但无法转换gzip压缩后的内容,导致报错
解决方法
- 修改feign配置,关闭 请求压缩 或者 增大 最小请求阈值长度
feign: compression: # 请求是否开启gzip压缩 request: enabled: false #最小请求阈值长度,超过该1024kb大小进行压缩 min-request-size: 1024 # 响应是否开启gzip压缩 response: enabled: true # 响应解码 useGzipDecoder: true - 新增过滤器,专门处理Content-Encoding为gzip的请求
MyGzipRequestWrapper
public class MyGzipRequestWrapper extends HttpServletRequestWrapper { private HttpServletRequest request; public MyGzipRequestWrapper(HttpServletRequest request) { super(request); this.request = request; } @Override public ServletInputStream getInputStream() throws IOException { ServletInputStream inputStream = request.getInputStream(); try { GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream); ServletInputStream newStream = new ServletInputStream() { @Override public boolean isFinished() { return false; } @Override public boolean isReady() { return false; } @Override public void setReadListener(ReadListener readListener) { } @Override public int read() throws IOException { return gzipInputStream.read(); } }; return newStream; } catch (Exception e) { } return inputStream; } }MyGzipFilter
public class MyGzipFilter implements Filter { @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) servletRequest; String contentEncoding = request.getHeader("Content-Encoding"); if (contentEncoding != null && !contentEncoding.isEmpty() && contentEncoding.contains("gzip")) { request = new MyGzipRequestWrapper(request); } System.out.println(request.getMethod()); filterChain.doFilter(request, servletResponse); } } - 使用原生的http,构造body去请求客户端的api