记录springboot+springcloud实际开发中需要注意的一些细节

用springboot+springcloud开发也有一年多了,记录一下心得,和一些需要注意的地方。

1.feign调用时,方法参数的@RequestParam里面必须要有value值
比如,你这个样子写就是不行滴:

@FeignClient("test-service") //这个地方是你要调用的服务的应用名(spring.application.name配置)
public interface TestClient {
 @RequestMapping(value = "/xxxxxx",  method = {RequestMethod.POST})
    public RespData testQuery(@RequestParam(value = "platformId") Long platformId,//必须要有value值
                                         @RequestParam(value = "groupId") String groupId);
}

这个地方和springmvc的@RequestParam处理方式不一样,springmvc的这个注解不填写value的时候,value默认就是后面的参数名;如果feign调用的时候不填,就会默认封装成map的方式去调用目标服务,这个时候由于目标方法接收参数的形式不是map,就会报这个错:

Caused by: java.lang.IllegalStateException: RequestParam.value() was empty on parameter 0

所以,feign调用时,@RequestParam里面必须要有value值

2.feign调用时,方法的@RequestMapping里面必须指定method,而且只能指定一个调用方式

@RequestMapping(value = "/xxxxxx",  method = {RequestMethod.POST})//这个地方需要设置method,确定feign具体的请求方式

这个也需要注意,写springmvc顺手了,会出现不设置method或者将method的值设置为多个

3.如果方法的返回值是对象,对象必须要有无参构造函数

 @RequestMapping(value = "/xxxxxx",  method = {RequestMethod.POST})
    public Student testQuery(@RequestParam(value = "platformId") Long platformId)//Student对象必须要有无参构造函数

feign将json反序列化为对象时默认使用的是fastjson,如果采用了@JsonCreator注解标注构造函数,那么在转对象时就会调用被@JsonCreator注解标注的构造函数;如果没有使用@JsonCreator注解标注,就默认调用对象的无参构造函数,对象没有无参构造函数就会报错:

com.fasterxml.jackson.databind.JsonMappingException

在开发时,也要注意这个坑!!!

4.feign调用,带上请求头信息的解决方案
项目就是微服务架构,服务之间调用的情况非常多,不同的服务涉及的接口访问权限也不一样,比如platform-service就需要系统用户登录,item-service都可以访问,user-service就需要普通用户登录。我们的解决方案就是每个服务都有自己的拦截器。
现在的问题就是一个服务调另外一个服务的时候,必须将请求头中的cookie信息带上,不然会被拦截器拦截。
现在提供两种解决方案:
第一种,就是所有的feign请求都会带上请求头中的信息(参考地址)

//定义一个拦截器,拦截到请求,然后获取请求头中的信息设置到requestTemplate中
//注意这个方法所在的类需要加@Configration注解
@Bean
    public RequestInterceptor headerInterceptor() {
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate requestTemplate) {
                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 values = request.getHeader(name);
                        requestTemplate.header(name, values);
                    }
                }
            }
        };
    }

//然后在application.yml中配置
hystrix:
  command:
    default:
      execution:
        isolation:
          strategy: SEMAPHORE //注意这个地方中间有个空格

第二种,设置某一次feign调用带上请求头中的信息(我们是采用的这个)

//定义一个类 实现RequestInterceptor接口,重写apply方法
@Override
	public void apply(RequestTemplate requestTemplate) {
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		if (requestAttributes == null) {
			return;
		}
		HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
		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);
				}
			}
		}
	}

//在具体生成feign时用这个方法生成
Feign.builder().encoder(new JacksonEncoder()).decoder(new JacksonDecoder())
			.options(new Request.Options(1000, 3500)).requestInterceptor(new FeignClientsConfigurationCustom())//定义的请求拦截器类
			.retryer(new Retryer.Default(5000, 5000, 3))
			.target(clazz,domain)//clazz->返回的feignClient接口  domain->feign前面的请求地址

目前就这些,有的忘了,后面遇到会补充上。

发布了42 篇原创文章 · 获赞 29 · 访问量 2553

猜你喜欢

转载自blog.csdn.net/qq_32314335/article/details/90080016