业务场景
前端请求时,会在请求头header
中带上一系列的校验参数,到达我负责的模块之后,需要去调用其他服务。在其他服务中, 需要对请求的请求头header
中的信息做相关校验以及信息提取,再执行相关业务行为。
问题描述
在我这边配好feign调用之后,发起调用,却发现返回500错误码,查看对应错误日志,被调用方对header
进行校验时NPE了,通过打印日志(嗯忘记直接debug看了)发现我方header中的信息参数都没有传过去。
思考过程
feign实质上也只是发起了一次请求罢了,底层也不过是对参数进行封装最后进行请求,正因为是一次新的请求,那么前端传入的请求中的头文件信息自然不会被传过去,那么我要做的就是找方法将前端请求中的头信息放到转发时候的请求里。
解决方案
写一个配置类,继承请求拦截器然后发起feign请求的时候把信息添加进去
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
/**
* @createTime: 2020.11.27 18:27
* @version: 1.0
*/
@Configuration
public class FeignClientConfiguration implements RequestInterceptor
{
@Override
public void apply(RequestTemplate requestTemplate)
{
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes == null) {
return;
}
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
//处理header信息
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
Enumeration<String> values = request.getHeaders(name);
while (values.hasMoreElements()) {
String value = values.nextElement();
requestTemplate.header(name, value);
}
}
}
//处理请求体参数信息
Enumeration<String> bodyNames = request.getParameterNames();
StringBuilder body = new StringBuilder();
if (bodyNames != null) {
while (bodyNames.hasMoreElements()) {
String name = bodyNames.nextElement();
String values = request.getParameter(name);
body.append(name).append("=").append(values).append("&");
}
}
if (body.length() != 0) {
body.deleteCharAt(body.length() - 1);
requestTemplate.body(body.toString());
}
}
}
最好在feign调用类上也指定一下用的配置类
@FeignClient(name = "server",configuration = FeignClientConfiguration.class)
public interface FeignServerService
{
//do something
}
补充
在我实装该功能之后,我又出现了一个新的错误:feign调用get接口的时候,竟然会报出405 Request method ‘POST‘ not supported
的错误 , 真的挺有趣的,然后在查资料的时候,看到了一个大佬的文章,总结了feign的几个坑,我才发现这东西这么好玩。
Request method ‘POST‘ not supported
解决方案如下:
当你不需要将请求体内的信息也传输过去的,可以把下面处理请求体信息的代码段注释掉
//处理请求体参数信息
/*
Enumeration<String> bodyNames = request.getParameterNames();
StringBuilder body = new StringBuilder();
if (bodyNames != null) {
while (bodyNames.hasMoreElements()) {
String name = bodyNames.nextElement();
String values = request.getParameter(name);
body.append(name).append("=").append(values).append("&");
}
}
if (body.length() != 0) {
body.deleteCharAt(body.length() - 1);
requestTemplate.body(body.toString());
}
*/
原因是feign底层发请求的时候,发现请求体带有参数会自动转成post请求。详细原因还请看大佬的这篇博客:https://blog.csdn.net/f641385712/article/details/82431502
,里面有逐步向下的分析和讲述。