FeignClient客户端执行请求后,服务端没有收到feign请求,客户端却显示请求成功,响应内容为null

项目场景:

政务管理系统,采用spring-cloud微服务架构,模块间采用feign进行互相调用,在其他模块调用用户管理模块查询用户信息时候,出现如下问题。


问题及解决

问题feign客户端示例代码如下:

@FeignClient(name = "sys-user-manage", fallback = UserClientFallback.class)
public interface IUserClient {

	String API_PREFIX = "/client";
	String USER_INFO_BY_ID = API_PREFIX + "/user-info-by-id";

	/**
	 * 获取用户信息
	 *
	 * @param userId 用户id
	 * @return
	 */
	@GetMapping(USER_INFO_BY_ID)
	User userInfoById(@RequestParam("userId") Long userId);

}

1.服务端没有收到feign请求。

  • 排查代码,发现服务端feign实现未注册http资源。问题代码示例如下:
@Slf4j
@Component
public class UserResource implements IUserClient {
    
    @Override
    public User userInfoById(Long userId) {
        return null;
    }
}

  • 解决方式为:将feign服务端实现注册为http资源(@RestController),示例代码如下:
@RestController
@Slf4j
public class UserResource implements IUserClient {

    @Override
    public User userInfoById(Long userId) {
        return null;
    }
}

2.客户端请求成功,内容为null。

  • 排查代码发现,FeignClient的fallback实现并未输出错误提示,问题代码示例如下:
@Slf4j
@Component
public class UserClientFallback implements IUserClient{
    @Override
    public User userInfoById(Long userId) {
        return null;
    }
}

  • 解决方式为,修改fallback实现方式为fallbackFactory跟踪回退触发器的原因,最终修改的示例代码如下:
@FeignClient(name = "sys-user-manage", fallbackFactory = UserClientFallBackFactory.class)
//@FeignClient(name = "sys-user-manage", fallback = UserClientFallback.class)
public interface IUserClient {

	String API_PREFIX = "/client";
	String USER_INFO_BY_ID = API_PREFIX + "/user-info-by-id";

	/**
	 * 获取用户信息
	 *
	 * @param userId 用户id
	 * @return
	 */
	@GetMapping(USER_INFO_BY_ID)
	User userInfoById(@RequestParam("userId") Long userId);
}

@Slf4j
@Component
class UserClientFallBackFactory implements FallbackFactory<IUserClient> {

	@Override
	public IUserClient create(Throwable cause) {
		return new IUserClient(){

			@Override
			public User userInfoById(Long userId) {
				log.error("userInfoById error", cause);
				return null;
			}
		};
	}
}


关于FeignResource

需要将FeignClient实现并注册为http资源。@FeignClient不应在服务器和客户端之间共享接口,并且不再支持在类级别上批注接口。@FeignClient@RequestMapping
。示例代码如下:

//Feign客户端
@FeignClient("users")
public interface UserClient {

    @RequestMapping(method = RequestMethod.GET, value ="/users/{id}")
    User getUser(@PathVariable("id") long id);
}
//feign服务端资源
@RestController
public class UserResource implements UserClient {

    @Override
    public User getUser(Long id) {
        //具体业务逻辑
        return null;
    }
}






关于FeignClient

1.写法

1.1.不推荐:不需要考虑feign客户端请求回退原因,可以使用如下方式,提供feign请求错误的默认代码路径,@FeignClientfallback。(该方式不方便feign客户端和资源端链接问题排查)。

@FeignClient(name = "test", url = "http://localhost:${server.port}/", fallback = Fallback.class)
    protected interface TestClient {

        @RequestMapping(method = RequestMethod.GET, value = "/hello")
        Hello getHello();

        @RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")
        String getException();

    }

    @Component
    static class Fallback implements TestClient {

        @Override
        public Hello getHello() {
            throw new NoFallbackAvailableException("Boom!", new RuntimeException());
        }

        @Override
        public String getException() {
            return "Fixed response";
        }

    }


1.2.推荐:如果需要访问进行回退触发器的原因,则可以使用 里面的属性,fallbackFactory@FeignClient。(该方式既能提供feign请求错误的默认代码路径,同时也能访问进行回退触发器的原因,方便问题排查。写法也可以参照上面问题2的内部实现方式。)

@FeignClient(name = "testClientWithFactory", url = "http://localhost:${server.port}/",
            fallbackFactory = TestFallbackFactory.class)
    protected interface TestClientWithFactory {

        @RequestMapping(method = RequestMethod.GET, value = "/hello")
        Hello getHello();

        @RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")
        String getException();

    }

    @Component
    static class TestFallbackFactory implements FallbackFactory<FallbackWithFactory> {

        @Override
        public FallbackWithFactory create(Throwable cause) {
            return new FallbackWithFactory();
        }

    }

    static class FallbackWithFactory implements TestClientWithFactory {

        @Override
        public Hello getHello() {
            throw new NoFallbackAvailableException("Boom!", new RuntimeException());
        }

        @Override
        public String getException() {
            return "Fixed response";
        }

    }


2.手动创建FeignClient。在某些情况下,可能不可以使用上述方法创建客户端。在这种情况下,您可以使用 Feign Builder API 创建客户端。下面是一个示例 它创建两个具有相同接口的 Feign 客户端,但为每个客户端配置 单独的请求拦截器。

@Import(FeignClientsConfiguration.class)
class FooController {

    private FooClient fooClient;

    private FooClient adminClient;

    @Autowired
    public FooController(Client client, Encoder encoder, Decoder decoder, Contract contract, MicrometerObservationCapability micrometerObservationCapability) {
        this.fooClient = Feign.builder().client(client)
                .encoder(encoder)
                .decoder(decoder)
                .contract(contract)
                .addCapability(micrometerObservationCapability)
                .requestInterceptor(new BasicAuthRequestInterceptor("user", "user"))
                .target(FooClient.class, "https://PROD-SVC");

        this.adminClient = Feign.builder().client(client)
                .encoder(encoder)
                .decoder(decoder)
                .contract(contract)
                .addCapability(micrometerObservationCapability)
                .requestInterceptor(new BasicAuthRequestInterceptor("admin", "admin"))
                .target(FooClient.class, "https://PROD-SVC");
    }
}


3.特殊参数

3.1.将 POJO 或 Map 参数注释为查询参数映射,Spring Cloud OpenFeign 提供了一个等效的注释@SpringQueryMap。示例如下:

// Params.java
public class Params {
    private String param1;
    private String param2;

    // [Getters and setters omitted for brevity]
}

@FeignClient("demo")
public interface DemoTemplate {

    @GetMapping(path = "/demo")
    String demoEndpoint(@SpringQueryMap Params params);
}


3.2.如果将map作为方法参数传递,则通过将map中的键值对用‘=’连接来创建@MatrixVariable路径段。示例代码如下:

@GetMapping("/objects/links/{matrixVars}")
Map<String, List<String>> getObjects(@MatrixVariable Map<String, List<String>> matrixVars);



Feign文档参照地址

1.Spring Cloud OpenFeign参照地址

2.OpenFeign参照地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mister-big

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值