本篇内容是关于SpringCloud的RPC调用方案中的OpenFeign使用过程的,我个人碰上的一个问题,希望对于一些刚接触这个矿机的朋友,有一定的启发作用;
这个问题是由于服务间的调用往往就涉及到请求头中一些参数的转发,常见例如:访问令牌;接下来,就是我在实际使用过程中对于请求头转发的处理和碰到问题的描述,相应的解决方式,希望能够为一些人提供借鉴。
- 请求头转发 处理
/**
* @author Eden4J
* @description Feign相关配置类
* @date 2021-09-25 11:00
*/
@Configuration
public class FeignConfig {
// feign的日志级别配置
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
//让DispatcherServlet向子线程传递RequestContext
@Bean
public ServletRegistrationBean<DispatcherServlet> dispatcherRegistration(DispatcherServlet servlet) {
servlet.setThreadContextInheritable(true);
return new ServletRegistrationBean<>(servlet, "/**");
}
//覆写拦截器,在feign发送请求前取出原来的header并转发,问题就是出现在复制之后
@Bean
public RequestInterceptor requestInterceptor() {
return (template -> {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//获取请求头
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String value = request.getHeader(name);
//直接复制请求头到模板
template.header(name, value);
}
}
});
}
- 出现的问题
A服务调用B服务时,在服务B上出现如下问题:
java.lang.IllegalArgumentException: Invalid character found in method name [XXXX]. HTTP method names must be tokens
- 解决方式
我首先先把feign间的调用日志全部打开,在控制台去看日志,果然发现了问题所在,所以开发一定要仔细去看日志,也学会去看日志,即使不知道怎么下手解决问题,能定位到问题就能更精准找到解决方案
如下图:
通过观察,发现了请求头有两个content-length,而且大小不一致;所以问题就是出在这个地方上,因为前端通过Ajax 提交会把content-length 带上来,在第1点中的拦截器中,又会把参数复制一遍,因此出现了两个content-length,其他如果有类似参数也会有此可能;所以最终解决的方式是在拦截器中把这个参数剔除,不做此项参数复制;其次如果是服务间的调用完全可以把没有必要的参数剔除,可以不用复制,例如是把content-type也剔除掉,
@Bean
public RequestInterceptor requestInterceptor() {
return (template -> {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String value = request.getHeader(name);
// 剔除content-length的复制
if (!"content-length".equalsIgnoreCase(name)) {
template.header(name, value);
}
}
}
});
}