我使用Spring-Cloud-Netflix进行微服务之间的通信.假设我有两个服务,Foo和Bar,而Foo使用Bar的REST端点之一.我使用一个带注释的接口@FeignClient:
@FeignClient
public interface BarClient {
@RequestMapping(value = "/some/url", method = "POST")
void bazzle(@RequestBody BazzleRequest);
}
Run Code Online (Sandbox Code Playgroud)
然后我SomeService在Foo中有一个服务类,它调用了BarClient.
@Component
public class SomeService {
@Autowired
BarClient barClient;
public String doSomething() {
try {
barClient.bazzle(new BazzleRequest(...));
return "so bazzle my eyes dazzle";
} catch(FeignException e) {
return "Not bazzle today!";
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,为了确保服务之间的通信正常工作,我想构建一个测试,使用WireMock之类的东西,对一个假的Bar服务器发出真正的HTTP请求.测试应确保假设正确解码服务响应并报告SomeService.
public class SomeServiceIntegrationTest {
@Autowired SomeService someService;
@Test
public void shouldSucceed() {
stubFor(get(urlEqualTo("/some/url"))
.willReturn(aResponse()
.withStatus(204);
String result = someService.doSomething();
assertThat(result, is("so …Run Code Online (Sandbox Code Playgroud) 这个外部呼叫我有一个假装客户端:
@RequestMapping(method = RequestMethod.GET, value = "GetResourceA", consumes = "application/json")
@Cacheable("ResourceA")
List<Stop> getResourceA() throws MyOwnException;
Run Code Online (Sandbox Code Playgroud)
在我的application.yml我有这个设置:
hystrix:
command:
default:
execution.isolation.thread.timeoutInMilliseconds: 1000
fallback.enabled: false
Run Code Online (Sandbox Code Playgroud)
现在,如果getResourceA超时,即完成时间超过一秒,我得到这个:
com.netflix.hystrix.exception.HystrixRuntimeException: getResourceA timed-out and no fallback available
Run Code Online (Sandbox Code Playgroud)
或者,如果我定义了一个我自己抛出异常的后备,我得到这个:
com.netflix.hystrix.exception.HystrixRuntimeException: getResourceA timed-out and fallback failed.
Run Code Online (Sandbox Code Playgroud)
我不能从后备中抛出自己的异常吗?
如果我希望在服务停止时抛出自己的异常怎么办?我想没有后备(因为我没有合理的价值从回退中返回),而是抛出我自己的错误,我可以抓住并让程序恢复.有人可以帮我解决这个问题吗?
Ben回答后更新:
所以我尝试了捕获HysterixRuntimeException并检查导致它的原因的方法,但最终得到了这个丑陋的代码:
try {
getResourceA();
} catch (HystrixRuntimeException e) {
if (e.getFailureType().name().equals("TIMEOUT")) {
throw new MyOwnException("Service timed out");
}
throw e;
}
Run Code Online (Sandbox Code Playgroud)
所有能够在超时时抛出MyOwnException的东西.肯定还有另一种方式吗?
我正在尝试为Feign rest客户端的每个请求进行日志记录.但是我无法使日志工作,而'标准'Slf4j日志记录确实有效.
我有以下内容:
public MyClient() {
initConnectionProperties();
this.service = Feign.builder()
.contract(new JAXRSContract())
.decoder(getJacksonDecoder())
.encoder(getJacksonEncoder())
.requestInterceptor(new BasicAuthRequestInterceptor(user, password))
//.client(new OkHttpClient())
.logger(new Slf4jLogger(MyClient.class)) //not working
.logLevel(feign.Logger.Level.BASIC)
.target(MyClient.class, this.url);
logger.info("Connection parameters: url = " + url + ", user = " + user); //Is working
}
Run Code Online (Sandbox Code Playgroud) 我有一些 fiegn 客户端发送请求其他微服务。
@FeignClient(name="userservice")
public interface UserClient {
@RequestMapping(
method= RequestMethod.GET,
path = "/userlist")
String getUserByid(@RequestParam(value ="id") String id);
}
Run Code Online (Sandbox Code Playgroud)
现在我正在发送这样的请求
try {
String responseData = userClient.getUserByid(id);
return responseData;
}
catch(FeignException e)
{
logger.error("Failed to get user", id);
}
catch (Exception e)
{
logger.error("Failed to get user", id);
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是,如果发生任何 FeignException,我不会收到任何错误代码。
我需要在其他 APIS 中发送相应的错误代码以发送给调用方
那么如何提取错误代码呢?我想提取错误代码并构建一个 responseEntity
我得到了这段代码,但不知道如何在我的函数中使用。
我需要向一些新的假客户端添加自定义授权标头。所以我编写了一个 RequestInterceptor 并且它起作用了,但重点是我不希望这个自定义 RequestInterceptor 影响我的旧客户端。我尝试使用 template.url() 方法进行过滤,但它没有给我请求的整个 url,它只包含客户端方法 url(不是客户端类上方宣布的 url 和路径)。我的问题是如何瞄准拦截器?
这是我的配置:
@Configuration
open class FeignCustomConfiguration {
private fun generateToken(): String { ... }
@Bean
open fun requestInterceptor(): RequestInterceptor {
return RequestInterceptor {
it.header("Authorization", generateToken())
}
}
}
Run Code Online (Sandbox Code Playgroud) 我最近使用netflix假装和功能区非常有用.
一个例子是:
@FeignClient(name = "ldap-proxy")
public interface LdapProxyClient {
@RequestMapping(path = "/ldap-proxy/v1/users/{userNameOrEMail}", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
LdapUser search(@PathVariable("userNameOrEMail") String userNameOrEMail);
}
Run Code Online (Sandbox Code Playgroud)
但是,在某些时候,我认为不必手动编写所有这些定义(对于现有的Web服务),我应该看看是否存在工具.
我偶然发现了https://github.com/swagger-api/swagger-codegen一些客户端生成的例子,例如https://github.com/swagger-api/swagger-codegen/tree/master/samples/client/petstore/java/feign.
但是,一旦我仔细查看了进口,我注意到以下情况:
import feign.Feign;
另一方面,Netflix的开源解决方案有包名:
org.springframework.cloud.netflix.feign.
另外,我注意到两者都使用功能区(如果可用),但Netflix的表示法更加清晰,后台发生了很多事情.例如,@FeignClient注释类javadoc声明:
- 接口的注释声明应该*创建具有该接口的REST客户端(例如,用于自动装配到另一个组件中).如果功能区可用,它将*用于对后端请求进行负载平衡,并且可以使用
@RibbonClient与feign客户端具有相同名称(即值)的a来配置负载均衡器.
但是在Feign.feign文档中(https://github.com/OpenFeign/feign),我看到:
RibbonClient覆盖了Feign客户端的URL解析,添加了Ribbon提供的智能路由和弹性功能.
集成要求您将功能区客户端名称作为URL的主机部分传递,例如myAppProd.
> MyService api =
> Feign.builder().client(RibbonClient.create()).target(MyService.class,
> "https://myAppProd");
Run Code Online (Sandbox Code Playgroud)
它们是完全不同的项目,没有关系,或者netflix只是分叉/利用OpenFeign并将其修改为在其集成云解决方案中?从本质上讲,netflix是否只是从开源项目中获取并集成了Discovery,Ribbon和feign等不同技术?
使用spring-mvc注释,如何定义可以POST form-url-encoded的@FeignClient?
每当我通过假装客户端发出请求时,我都希望为我的身份验证用户设置一个特定的标头.
这是我的过滤器,我从中获取身份验证并将其设置为spring安全上下文:
@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients
public class PerformanceApplication {
@Bean
public Filter requestDetailsFilter() {
return new RequestDetailsFilter();
}
public static void main(String[] args) {
SpringApplication.run(PerformanceApplication.class, args);
}
private class RequestDetailsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String userName = ((HttpServletRequest)servletRequest).getHeader("Z-User-Details");
String pass = ((HttpServletRequest)servletRequest).getHeader("X-User-Details");
if (pass != null)
pass = decrypt(pass);
SecurityContext secure = new SecurityContextImpl();
org.springframework.security.core.Authentication token = new UsernamePasswordAuthenticationToken(userName, …Run Code Online (Sandbox Code Playgroud) 我正在编写的微服务需要与我们平台中的其他微服务进行通信.在那次尝试中,我们的理想解决方案是Spring Cloud Netflix Feign,实现了一个@FeignClient.
但是,当我尝试以下时,我正面临以下例外@Autowired ReviewProvider:
例外(原因)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.cloud.netflix.feign.FeignContext' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:353)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:351)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:340)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1093)
at org.springframework.cloud.netflix.feign.FeignClientFactoryBean.getObject(FeignClientFactoryBean.java:155)
at org.springframework.beans.factory.support.FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(FactoryBeanRegistrySupport.java:168)
Run Code Online (Sandbox Code Playgroud)
ReviewProvider.java
@FeignClient("http://metadata-reviews")
public interface ReviewProvider {
@RequestMapping(path = "sessions", method = POST)
ReviewSessionDTO createSession();
}
Run Code Online (Sandbox Code Playgroud)
ReviewProvider.java
@RunWith(SpringRunner.class)
@ActiveProfiles(INTEGRATION)
@ContextConfiguration(classes = AppEntry.class)
@AutoConfigureTestDatabase(replace = Replace.NONE)
@DataJpaTest
public class ReviewProviderTest {
@Autowired
private ReviewProvider provider;
private Class<? extends ReviewProvider> providerClass;
@Before
public void setup() {
providerClass = …Run Code Online (Sandbox Code Playgroud) java spring-boot spring-cloud-feign feign spring-cloud-netflix
我目前正在手动构建一个假装客户端并将拦截器传递给它进行授权.我想为一些响应代码提供更智能的Retryer.
public class myErrorEncoder extends ErrorDecoder.Default {
@Override
public Exception decode(final String methodKey, final Response response) {
if (response.status() == 401) {
String token = refreshToken(); // I would like to refresh the token and Edit the client
return new RetryableException("Token Expired will retry it", null);
} else {
return super.decode(methodKey, response);
}
}
Run Code Online (Sandbox Code Playgroud)
}
拦截器
@Bean public CustomInterceptor getInterceptor(String token) {
return new CustomInterceptor(token);}
Run Code Online (Sandbox Code Playgroud)
假装建设者
private <T> T feignBuild(final Class<T> clazz, final String uri, final String token) {
return …Run Code Online (Sandbox Code Playgroud) feign ×10
java ×7
spring ×2
spring-boot ×2
spring-cloud ×2
exception ×1
header ×1
hystrix ×1
interceptor ×1
kotlin ×1
spring-mvc ×1
wiremock ×1