Controller

必须用@RestController不能用@Controller

SpringCloud的RPC是基于json(用的RestTemplate)的,所有用到RPC(ribbon或feign)的Controller,必须用@RestControlelr,不能用@Controller,否则调用方会报错,例如:

feign.FeignException$NotFound: status 404 reading UserFeignService#getUser(Long)

 继而产生的影响:默认情况下:feign接口及feign服务提供者都是@RequestBody,只能有一个参数。若想改变,则必须在每一个参数前边加@RequestParam

Feign接口

版本问题

有的老版本不支持@GetMapping等组合注解,需要@RequestMapping(method = RequestMethod.GET)

@PathVariable 

使用@PathVariable时,需要指定其value。否则会报错:Caused by: java.lang.IllegalStateException: PathVariable annotation was empty on param 0

public String findServiceName(@PathVariable("Name") String Name);

@RequestParam

请求方法

        默认情况下,Feign会将标有@RequestParam注解的参数转换成字符串添加到URL中,将没有注解的参数通过Jackson转换成json放到请求体中(无论是指定了get还是post)。

        如果请求方式指定为POST,那么所有未标注解的参数将会被忽略,所以这里的@RequestMapping必须指定。必须指定value的值,否则将报QueryMap parameter must be a Map错误。

        如果请求方式指定为GET,则必须添加@RequestParam,否则,将报错:Request parameter of Get can't be a body。

指定名称

若不指定名称有时会报错:

@RequestMapping("/greeting")
String greeting(@RequestParam String name);

 报错信息

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'com.example.UserFeignClient': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalStateException: RequestParam.value() was empty on parameter 0

解决方法:

@RequestMapping("/greeting")
String greeting(@RequestParam("name") String name);

调用同一个服务的接口要放到一个feign接口中

错误写法

@FeignClient("user")
public interface TestLongFeignService {
@PostMapping("/user/long")
public ResultWrapper testLong(String param1);
}
@FeignClient("user")
public interface UserFeignService {
@GetMapping("/user/{id}")
public User getUser(@PathVariable("id") Long id);
}

错误日志: 

The bean 'user.FeignClientSpecification' could not be registered. A bean with that name has already been defined and overriding is disabled.

应该这样写

@FeignClient("user")
public interface UserFeignService {
@GetMapping("/user/{id}")
public User getUser(@PathVariable("id") Long id);

@PostMapping("/user/long")
public ResultWrapper testLong(String param1);
}

参数长度问题

描述

如果参数过长,会报错:

调用端报错:     feign.FeignException: status 400 reading xxx#xxxx(

被调用端报错: java.lang.IllegalArgumentException: Request header is too large

复现

浏览器访问:​​http://localhost:9001/product/long​

调用者

@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
UserFeignService userFeignService;

@GetMapping("/long")
public ResultWrapper testLong(){
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < 10000; i++) {
stringBuffer.append(i % 10);
}
StringBuffer stringBuffer2 = new StringBuffer();
for (int i = 0; i < 10000; i++) {
stringBuffer2.append(i % 5);
}
ResultWrapper resultWrapper = userFeignService.testLong(stringBuffer.toString(),
stringBuffer2.toString());
return resultWrapper;
}
}
@FeignClient("user")
public interface UserFeignService {
@PostMapping("/user/long")
public ResultWrapper testLong(@RequestParam String param1, @RequestParam String param2);
}

被调用者

@RestController
@RequestMapping("/user")
public class UserController {
private Logger logger = Logger.getLogger(String.valueOf(getClass()));

@Autowired
private DiscoveryClient discoveryClient;

@PostMapping("/long")
public ResultWrapper testLong(@RequestParam String param1, @RequestParam String param2) {
System.out.println(param1);
System.out.println(param2);
List<String> stringList = new ArrayList<>();
stringList.add(param1);
stringList.add(param2);
return new ResultWrapper().success(true).message("成功").object(stringList);
}
}

解决方法

法1(不推荐):修改Tomcat配置,把header的值改大

法2(推荐):将其放到一个类中。

法3(最推荐):自定义HttpMessageConverter。使用Map<String, Object>来传输。

HttpMessageConverter

其他网址


示例代码对应网址:​​https://gitee.com/shapeless/demo_SpringCloud​

如果传输数据很大,最好放到一个类中,直接使用JSON传输,但这样做有个缺点:每次都要将参数封装到一个类中,很麻烦。解决方法:自定义HttpMessageConverter,若有多个参数,可用Map<String, Object>。

Feign--基础_spring

调用端

配置(只在调用端配置即可)

package com.example.product.config;

import feign.Logger;
import feign.form.spring.SpringFormEncoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignConfiguration {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;

@Bean
public SpringFormEncoder feignFormEncoder() {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}

@Bean
public Logger.Level logger() {
// 为了方便问题排查,把http的请求和响应全部打印出来
return Logger.Level.FULL;
}
}
package com.example.product.feign;

import com.example.product.entity.LongDTO;
import com.example.product.entity.ResultWrapper;
import com.example.product.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;

import java.util.Map;
//如果这样写,则FeignConfiguration.java就不用@Configuration了
//@FeignClient(name = "user", configuration = FeignConfiguration.class)
@FeignClient(name = "user")
public interface UserFeignService {
@GetMapping("/user/{id}")
public User getUser(@PathVariable("id") Long id);

@PostMapping(value = "/user/long1")
public ResultWrapper testLong(LongDTO longDTO);

//下边这两种都可以
// @PostMapping(value = "/user/long3", headers = "content-type=application/x-www-form-urlencoded")
@PostMapping(value = "/user/long2", consumes = {"application/x-www-form-urlencoded"})
public ResultWrapper testLong(Map<String, ?> map);

// @PostMapping(value = "/user/long2", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
@PostMapping(value = "/user/long3")
public ResultWrapper testLong(MultiValueMap<String, Object> map);
}
package com.example.product.controller;

import com.example.product.entity.LongDTO;
import com.example.product.entity.ResultWrapper;
import com.example.product.entity.User;
import com.example.product.feign.UserFeignService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
UserFeignService userFeignService;

@GetMapping("/long2")
public ResultWrapper testLong2(){
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("abc").append(",").append("defg");

StringBuffer stringBuffer2 = new StringBuffer();
for (int i = 0; i < 10000; i++) {
stringBuffer2.append(String.valueOf(i % 10));
}
Map<String, Object> map = new HashMap<>();
map.put("param1", stringBuffer.toString());
map.put("param2", stringBuffer2.toString());

System.out.println(map);

ResultWrapper resultWrapper = userFeignService.testLong(map);
return resultWrapper;
}
}

被调用端

package com.example.user.controller;

import com.example.user.entity.LongDTO;
import com.example.user.entity.ResultWrapper;
import com.example.user.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

//必须用这个,不能用@Controller。
@RestController
@RequestMapping("/user")
public class UserController {
private Logger logger = Logger.getLogger(String.valueOf(getClass()));

@Autowired
private DiscoveryClient discoveryClient;

@PostMapping("/long2")
public ResultWrapper testLong2(String[] param1, String param2) {
System.out.println("param1: ");
for (String string : param1) {
System.out.println(string);
}
System.out.println();
System.out.println("param2: " + param2);

return new ResultWrapper().success(true).message("成功");
}
}

postman访问 ​​http://localhost:9001/product/long2​

结果:

user端(被调用端)打印结果

param1: 
abc
defg

param2: 0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789

注意:通过Map传数据时,value不能为null

@FallbackReturn(impl = CommonFeignFallback.class)
@FeignClient(value = "common", fallbackFactory = CommonFeignFallbackFactory.class)
public interface CommonFeignService {
@PostMapping(value = "/abc/def", headers = "content-type=application/x-www-form-urlencoded")
ResultWrapper sendQRCode(Map<String, ?> params);
}
Map<String, Object> map = new HashMap<>();
map.put("title", "This is Title");
map.put("content", null);

日志

Caused by: java.lang.NullPointerException: message
at feign.Util.checkNotNull(Util.java:114)
at feign.codec.EncodeException.<init>(EncodeException.java:32)
at feign.form.FormEncoder.encode(FormEncoder.java:96)
at feign.form.spring.SpringFormEncoder.encode(SpringFormEncoder.java:64)
at feign.ReflectiveFeign$BuildEncodedTemplateFromArgs.resolve(ReflectiveFeign.java:372)
... 42 common frames omitted

解决方法

将值为null的项删掉。

Map<String, Object> map = new HashMap<>();
map.put("title", "This is Title");

feign与zuul

        一般情况下,@FeignClient的name属性指定为特定服务的微服务名,这样在调用时不会通过zuul,此时可以将name直接指定为网关微服务名,这样就可以经过zuul,从而可以使用zuul的鉴权、过滤等功能。

指定为特定微服务

package com.example.product.feign;

import java.util.Map;

@FeignClient(name = "user")
public interface UserFeignService {
@GetMapping("/user/{id}")
public User getUser(@PathVariable("id") Long id);
}

指定为zuul微服务

package com.example.product.feign;

import java.util.Map;

@FeignClient(name = "zuul")
public interface UserFeignService {
@GetMapping("/user/{id}")
public User getUser(@PathVariable("id") Long id);
}