Spring Cloud Feign report 404 - spring-boot

I use Eureka to register a service and use Feign to discover services, but if I don't add URL parameters, the system will report 404 exceptions.
And my code id below that does not work :
#FeignClient(name = "CRAWLER-SERVICE")
And Below code works :
#FeignClient(name = "crawler-service", url = "http://192.168.199.229:8091/crawler")
Stack trace :
feign.FeignException: status 404 reading CrawlerServiceApi#queryAllConditions(String,String)
at feign.FeignException.errorStatus(FeignException.java:62) ~[feign-core-9.5.0.jar:na]
at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:91) ~[feign-core-9.5.0.jar:na]
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:138) ~[feign-core-9.5.0.jar:na]
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76) ~[feign-core-9.5.0.jar:na]
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103) ~[feign-core-9.5.0.jar:na]
at com.sun.proxy.$Proxy120.queryAllConditions(Unknown Source) ~[na:na]
at com.gezizhi.boss.controller.CrawlerConditionController.queryAllSource(CrawlerConditionController.java:29) ~[classes/:na]
at com.gezizhi.boss.controller.CrawlerConditionController$$FastClassBySpringCGLIB$$bd843b81.invoke(<generated>) ~[classes/:na]
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ~[spring-core-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) [spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
at org.springframework.aop.aspectj.MethodInvocationProceedingJoinPoint.proceed(MethodInvocationProceedingJoinPoint.java:85) ~[spring-aop-4.3.13.RELEASE.jar:4.3.13.RELEASE]
The eureka configuration is:
server:
port: 8761
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetch-registry: false
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
server:
enable-self-preservation: false
wait-time-in-ms-when-sync-empty: 0
And the client configuration is:
eureka:
instance:
lease-expiration-duration-in-seconds: 2
lease-renewal-interval-in-seconds: 1
client:
serviceUrl:
defaultZone: http://127.0.0.1:8761/eureka/
The server code:
#RestController
#RequestMapping("/api/crawler")
public class CrawlerConditonApi {
private final CrawlerConditonService crawlerConditonService;
#Autowired
public CrawlerConditonApi(CrawlerConditonService crawlerConditonService) {
this.crawlerConditonService = crawlerConditonService;
}
#GetMapping("/conditions")
public String queryAllConditions(String belongDatasource, String conditionStatus) {
return crawlerConditonService.queryAllCondition(belongDatasource, conditionStatus);
}
#PostMapping("/conditions")
public String insertConditon(String params, String belongDatasource) {
return crawlerConditonService.insertConditon(params, belongDatasource);
}
#PutMapping("/conditions/{id}/status/{status}")
public String updateCondition(#PathVariable("id") String id, #PathVariable("status") String status) {
return crawlerConditonService.updateCondition(id, status);
}
}
THE CLIENT CODE:
#FeignClient(name = "CRAWLER-SERVICE")
public interface CrawlerServiceApi {
#RequestMapping(value = "/api/papersources/", method = RequestMethod.GET)
String queryAllSource();
#RequestMapping(value = "/api/papersources/{id}/status/{status}", method = RequestMethod.PUT)
String updateSource(#PathVariable("id") String id, #PathVariable("status") String status);
#RequestMapping(value = "/api/crawler/conditions", method = RequestMethod.GET)
String queryAllConditions(#RequestParam("belongDatasource") String belongDatasource,
#RequestParam("conditionStatus") String conditionStatus);
#RequestMapping(value = "/api/crawler/conditions", method = RequestMethod.POST)
String insertConditon(#RequestParam("params") String params,
#RequestParam("belongDatasource") String belongDatasource);
#RequestMapping(value = "/api/crawler/conditions/{id}/status/{status}", method = RequestMethod.PUT)
String updateCondition(#PathVariable("id") String id, #PathVariable("status") String status);
}
And I use in Controller:
#RestController
public class CrawlerConditionController {
private final CrawlerServiceApi crawlerServiceApi;
#Autowired
public CrawlerConditionController(CrawlerServiceApi crawlerServiceApi) {
this.crawlerServiceApi = crawlerServiceApi;
}
#GetMapping("/conditions/query")
public AbstractResult queryAllSource(#RequestParam("belongDatasource") String belongDatasource,
#RequestParam("conditionStatus") String conditionStatus) {
return ApiInvokeRspUtil.returnDataRowsInvokeRsp("CRL00000",
crawlerServiceApi.queryAllConditions(belongDatasource, conditionStatus));
}
#PostMapping("/conditions/add")
public AbstractResult addConditon(#RequestParam("paramJson") String paramJson,
#RequestParam("belongDataSource") String belongDataSource) {
return ApiInvokeRspUtil.returnDataRowsInvokeRsp("CRL00000",
crawlerServiceApi.insertConditon(paramJson, belongDataSource));
}
#PostMapping("/conditions/{id}/status/{status}")
public AbstractResult updateConditon(#PathVariable("id") String id,
#PathVariable("status") String status) {
return ApiInvokeRspUtil.returnDataRowsInvokeRsp("CRL00000",
crawlerServiceApi.updateCondition(id, status));
}
}
application.yml which contain CrawlerConditonApi's project
server:
context-path: /crawler
port: 8091
eureka:
instance:
lease-expiration-duration-in-seconds: 2
lease-renewal-interval-in-seconds: 1
client:
serviceUrl:
defaultZone: http://127.0.0.1:8761/eureka/
spring:
datasource:
driver-class-name: org.mariadb.jdbc.Driver
url: jdbc:mysql://localhost:3306/gezizhi?useUnicode=true&characterEncoding=utf-8
username: root
password: password
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,wall,log4j
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
redis:
database: 0
host: 127.0.0.1
port: 6379
password: password
pool:
max-idle: 10
max-wait: 10000
max-active: 1024
min-idle: 1
timeout: 3000
application:
name: crawler-service
mybatis:
type-aliases-package: com.gezizhi.crawler.dao.domain
mapper-locations: classpath:mybatis/*.xml

It's an old question, still posting my answer so it may help someone else as I had the same problem and finally was able to solve it.
It happened due to server.context which is set to crawler. Since this effectively adds a new url segment, you need to change your feign client to below (mind the context added after service name)
#FeignClient(name = "CRAWLER-SERVICE/crawler")
Or you need to change the RequestMapping to something like below (again mind the context added before service url):
#RequestMapping("crawler/<rest of the url>")

Related

Retaining the Request's Path During Spring Cloud Gateway Failover

Is there a way to externally configure Spring Cloud Gateway to failover to another data center? I'm thinking of something like this:
spring:
cloud:
gateway:
routes:
- id: test-service
uri: lb://test-service:8085/
predicates:
- Path=/test-service/**
filters:
- StripPrefix=1
- name: CircuitBreaker
args:
name: fallback
fallbackUri: forward:/fallback
#fallbackUri: forward:/fallback/test-service
- id: fallback
uri: http://${fallback_data_center}
predicates:
- Path=/fallback/**
---
spring:
config:
activate:
on-profile: data_center_1
fallback_data_center: dc2.com
---
spring:
config:
activate:
on-profile: data_center_2
fallback_data_center: dc1.com
The problem I run into is that the CircuitBreaker filter's fallbackUri parameter only supports forward schemed URIs. However, the path part of the request URL is overridden with the path in the forward URL. So there does not appear to be a way to failover with the path from the original request such as if this configuration had received a request of http://dc1.com/test-service/some/path without creating a configuration for every possible path.
At the time of writing this answer there is still now official way of doing a failover to another host.
What we are trying to achieve in our team is to have routes with Retry and CircuitBreaker filters which can fallback to another host keeping the original request unmodified ( request payload, header, query params and most importantly the API context path ) and just replacing the host so we can fallback to another datacenter.
We archived this by using the default Gateway Retry and CircuitBreaker filters and developing a custom FallbackController which just replaces the host with a configured property and keeps the rest of the request unmodified including the request context path:
#RestController
#RequestMapping("/fallback")
#ConditionalOnProperty(value="gateway.fallback.enabled", havingValue = "true")
public class FallbackController {
private final GatewayFallbackConfig gatewayFallbackConfig;
private final WebClient webClient;
public FallbackController(GatewayFallbackConfig gatewayFallbackConfig) {
this.gatewayFallbackConfig = gatewayFallbackConfig;
this.webClient = WebClient.create();
}
#PostMapping
Mono<ResponseEntity<String>> postFallback(#RequestBody(required = false) String body,
ServerWebExchangeDecorator serverWebExchangeDecorator) {
return fallback(body, serverWebExchangeDecorator);
}
#GetMapping
Mono<ResponseEntity<String>> getFallback(#RequestBody(required = false) String body,
ServerWebExchangeDecorator serverWebExchangeDecorator) {
return fallback(body, serverWebExchangeDecorator);
}
#PatchMapping
Mono<ResponseEntity<String>> patchFallback(#RequestBody(required = false) String body,
ServerWebExchangeDecorator serverWebExchangeDecorator) {
return fallback(body, serverWebExchangeDecorator);
}
#DeleteMapping
Mono<ResponseEntity<String>> deleteFallback(#RequestBody(required = false) String body,
ServerWebExchangeDecorator serverWebExchangeDecorator) {
return fallback(body, serverWebExchangeDecorator);
}
private Mono<ResponseEntity<String>> fallback(String body, ServerWebExchangeDecorator serverWebExchangeDecorator) {
ServerHttpRequest originalRequest = serverWebExchangeDecorator.getDelegate().getRequest();
WebClient.RequestBodySpec request = webClient.method(originalRequest.getMethod())
.uri(buildFallbackURI(originalRequest));
Optional.ofNullable(body)
.ifPresent(request::bodyValue);
return request.exchangeToMono(response -> response.toEntity(String.class));
}
private URI buildFallbackURI(ServerHttpRequest originalRequest) {
return UriComponentsBuilder.fromHttpRequest(originalRequest)
.scheme(gatewayFallbackConfig.getScheme())
.host(gatewayFallbackConfig.getHost())
.port(gatewayFallbackConfig.getPort())
.build(ServerWebExchangeUtils.containsEncodedParts(originalRequest.getURI()))
.toUri();
}
With an additional property configuration holder:
#Getter
#Component
#RefreshScope
#ConditionalOnProperty(value="gateway.fallback.enabled", havingValue = "true")
public class GatewayFallbackConfig {
private final String scheme;
private final String host;
private final String port;
private final Set<String> excludedHeaders;
public GatewayFallbackConfig(
#Value("${gateway.fallback.scheme:https}") String scheme,
#Value("${gateway.fallback.host}") String host,
#Value("${gateway.fallback.port:#{null}}") String port,
#Value("${gateway.fallback.headers.exclude}") Set<String> excludedHeaders) {
this.scheme = scheme;
this.host = host;
this.port = port;
this.excludedHeaders = excludedHeaders;
}
And we are using it with a route configuration like that:
- id: example-route
uri: http://localhost:8080
predicates:
- Path=/foo/bar/**
filters:
- name: CircuitBreaker
args:
name: exampleCircuitBreaker
fallbackUri: forward:/fallback
statusCodes:
- INTERNAL_SERVER_ERROR
- BAD_GATEWAY
- SERVICE_UNAVAILABLE
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY,SERVICE_UNAVAILABLE,GATEWAY_TIMEOUT
series: SERVER_ERROR
methods: GET,POST,PUT,DELETE
exceptions: org.springframework.cloud.gateway.support.NotFoundException,javax.security.auth.login.LoginException
backoff:
firstBackoff: 10ms
maxBackoff: 50ms
factor: 2
basedOnPreviousValue: false
gateway:
fallback:
scheme: https
host: some.other.host.com
enabled: true

Spring Boot: Connection timed out when trying to call a service from a service

I have 2 microservices + an Eureka Server in which they are registerd.
I made really everything I could think of, yet when I try to call the login service from the manager service, I always get "Connection timed out".
POST http://localhost:9903/login
{
"username":"adm4",
"password":"adm4adm4"
}
I have tried to work with Spring RestTemplate and WebClient and also Apache HttpClient.
All the times, the flow reaches the post method, and I get the same result.
I guess it must be some configuration issue.
I am working on localhost with all modules.
It really drives me crzay!
Please advise. I appreciate it.
The relevant info is as follows. Please tell me if you need more info.
First of all you can see that the services are registered and up:
Next the code:
Manager (calling) Service:
(I left inside all my previous attempts commented)
#PostMapping("/login")
public void login(#RequestBody LoginRequest loginRequest) throws Exception {
String url = getBaseUrl("bbsim-login-service") + "/api/auth/signin";
/* CloseableHttpClient httpclient = HttpClients.createDefault();
try {
HttpPost httpPost = new HttpPost(getBaseUrl("bbsim-login-service") + "/api/auth/signin");
List<NameValuePair> params = new ArrayList<>();
params.add(new BasicNameValuePair("username", loginRequest.getUsername()));
params.add(new BasicNameValuePair("password", loginRequest.getPassword()));
httpPost.setEntity(new UrlEncodedFormEntity(params));
CloseableHttpResponse response = httpclient.execute(httpPost);
System.out.println(response.getStatusLine().getStatusCode());
} finally {
httpclient.close();
}
*/
/* HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
// Connect timeout: time is in milliseconds
clientHttpRequestFactory.setConnectTimeout(30000);
// Read timeout: time is in milliseconds
clientHttpRequestFactory.setReadTimeout(30000);
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
HttpEntity<LoginRequest> request = new HttpEntity<>(loginRequest);
JwtResponse res = restTemplate.postForObject(url, request, JwtResponse.class);
System.out.println(res);
*/
localApiClient
.post()
.uri(url)
.body(Mono.just(loginRequest), LoginRequest.class)
.retrieve()
.bodyToMono(JwtResponse.class)
.block();
}
private String getBaseUrl(String serviceName) {
Application application = eurekaClient.getApplication(serviceName);
InstanceInfo instanceInfo = application.getInstances().get(0);
String hostname = instanceInfo.getHostName();
int port = instanceInfo.getPort();
return "http://" + hostname + ":" + port;
}
application.yml:
server.port: 9903
spring:
application.name: bbsim-manager-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://localhost:8088/eureka}
registryFetchIntervalSeconds: 1
# register-with-eureka: true
# fetch-registry: true
instance:
leaseRenewalIntervalInSeconds: 1
If I understand well, the request does not reach the login service at all.
Login (called) service:
#PostMapping("/signin")
public ResponseEntity<?> authenticateUser(#Valid #RequestBody LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtUtils.generateJwtToken(authentication);
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
List<String> roles = userDetails.getAuthorities().stream()
.map(item -> item.getAuthority())
.collect(Collectors.toList());
return ResponseEntity.ok().body(new JwtResponse(jwt,
userDetails.getId(),
userDetails.getUsername(),
userDetails.getEmail(),
roles));
}
application.yml file:
server.port: 9902
spring:
application:
name: bbsim-login-service
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8088/eureka/
registryFetchIntervalSeconds: 1
instance:
leaseRenewalIntervalInSeconds: 1
I addition, I tried the following - giving me the same results:
curl -d "#data.json" -H "Content-Type: application/json" -X POST http://localhost:9903/login
where data.json has the body contents.
This will not be a complete answer but I hope it helps you with your issue.
I think your problem could be related with a mix of the different IP address of your machine.
First, I think Eureka is exposing your services like host.docker.internal, as indicated, the logical name that references the host machine through the different docker containers, for the reason explained in this SO question.
Basically, it seems that the docker software is updating your hosts file with entries for host.docker.internal and gateway.docker.internal and Eureka probably is taking that alias as the one for the machine IP that is being advertised. Please, see the accepted answer in the aforementioned question.
When you run Spring Boot normally the underlying server (Tomcat, Jetty, Undertow) will listen for connections in the 0.0.0.0 address, i.e., in all the network interfaces available, including localhost. This is what troubles me, because as indicated, the service should be accessible through all the IPs in the machine.
In any way, I think you can try several things to solve your issue.
Probably the best approach to solve the problem will be to configure the hostname of your Eureka server and/or your Eureka clients to a common one.
For example, you can configure your server and clients to be exposed as localhost.
For that purpose, you need to include the following configuration property in their respective config files:
eureka:
instance:
hostname: localhost
Looks like you are using Docker. You are trying to connect to localhost but other services are running in other container hence localhost won’t work. Would you please try 0.0.0.0 or host.docker.internal in your YAML file and see if that will work.
In other words you will need to edit following.
server.port: 9903
spring:
application.name: bbsim-manager-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://host.docker.internal:8088/eureka}
registryFetchIntervalSeconds: 1
# register-with-eureka: true
# fetch-registry: true
instance:
leaseRenewalIntervalInSeconds: 1
or change EUREKA_URI env variable to reflect that. Also in your service YAML
server.port: 9902
spring:
application:
name: bbsim-login-service
eureka:
client:
serviceUrl:
defaultZone: ${EUREKA_URI:http://host.docker.internal:8088/eureka/}
registryFetchIntervalSeconds: 1
instance:
leaseRenewalIntervalInSeconds: 1

How to resolve "SSLV3_ALERT_BAD_CERTIFICATE" error in Spring Boot

I have the following rest end point exposed protected by SSL (Spring Boot)
#RestController
public class TestController {
#RequestMapping(value = "/data", method = RequestMethod.GET)
public String getData() {
return "Hello World";
}
In YML I have the following properties
server:
ssl:
enabled: true
client-auth: need
key-store: {keystore-path}
key-store-password: {keystore-password}
key-alias: alias-name
key-store-type: JKS
Now I am trying to call the above rest end point from another app with the following code
URL obj = new URL(GET_URL);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
System.out.println("GET Response Code :: " + responseCode);
But I am getting the following error :
Error: write EPROTO 2771201016:error:10000410:SSL routines:OPENSSL_internal:SSLV3_ALERT_BAD_CERTIFICATE:../../third_party/boringssl/src/ssl/tls_record.cc:587:SSL alert number 42`
How to resolve this error?

zuul eureka service id redirection

I am having few spring boot microservices, which are deployed to JBoss over a cloud environment. These boot services are Eureka clients which register itself in to the Eureka server. Following is an example:
eureka:
client:
healthcheck:
enabled: true
serviceUrl:
defaultZone: ${DISCOVERY_URL:http://localhost:8761}/eureka/
instance:
ip-address: 127.0.0.1
appname: user-regn-service-app
home-page-url-path: /user-regn-service-app
It registers the app with Eureka with the name user-regn-service-app
Eureka Homepage
The wildfly server is running at 8080 and the user-regn-service-app is deployed at the context path /user-regn-service-app.
So the rest api is as below
localhost:8080/user-regn-service-app/regnUser
When I am using zuul as api gateway, the config is as below
zuul:
prefix: /api
routes:
test:
path: /test/**
service-id: USER-REGN-SERVICE-APP
strip-prefix: true
ribbon:
eureka:
enabled: true
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
registerWithEureka: false
But whenever I am making call to zuul api gateway it is unable to recognize the context path and redirects to localhost:8080 instead of localhost:8080/user-regn-service-app.
http://localhost:8765/api/ -> 404 not found
http://localhost:8765/api/user-regn-service-app/ -> Wildfly default homepage
http://localhost:8765/api/user-regn-service-app/user-regn-service-app/regnUser -> Redirects to user registration.
Expected behavior: http://localhost:8765/api/test/regnUser should redirect to the user registration.
I have pretty much tried all combinations that I got from blogs between Zuul and Eureka to get the following done but no luck. Kindly advise if I am missing something.
I have tried using custom zuul custom filter as below but it doesn't forward to the Required Context path. Code is as below
#Component
public class ZuulApiFilter extends ZuulFilter{
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
System.out.println("original"+ ctx.get("requestURI"));
HttpServletRequest request = ctx.getRequest();
String requestURI = request.getRequestURI();
String contextAwareURI=requestURI.concat("user-regn-service-app/");
ctx.set("requestURI", contextAwareURI);
return null;
}
#Override
public boolean shouldFilter() {
return true;
}
#Override
public int filterOrder() {
return 1;
}
#Override
public String filterType() {
return "pre";
}
}
The requestURI doesn't changes after setting the new URI as well
ctx.set("requestURI", contextAwareURI);
request.getRequestURI(); shows the old Request URI only.
Could you remove ZuulApiFilter and try setting:
strip-prefix: false
and try sending the request to:
http://<zuul ip>:<zuul port>/api/test/....
Edited:
#Tanmay Ghosh
Here is a sample code I'm using for Zuul-related blog post (still in draft) that I'll publish in the next couple of days:
Zuul's application.yml:
...
eureka:
client:
registerWithEureka: false
fetchRegistry: true
serviceUrl:
defaultZone: http://localhost:8000/eureka/
# ribbon.eureka.enabled: false
zuul:
ignoredServices: "*"
routes:
zuulDemo1:
path: /zuul1/**
# serviceId as registed with Eureka. Enabled and used when ribbon.eureka.enabled is true.
serviceId: demo-zuul-api1
# zuul.routes.<the route>.url used when ribbon.eureka.enabled is false, serviceId is disabled.
# url: http://localhost:8600/
# stripPrefix set to true if context path is set to /
stripPrefix: true
...
And actually my Zuul server repo is public and available at: https://bitbucket.org/asimio/zuulserver and a recent blog post at http://tech.asimio.net/2017/10/10/Routing-requests-and-dynamically-refreshing-routes-using-Spring-Cloud-Zuul-Server.html
Another thing, Does the Zuul service also uses an app context other than / ? If so, Could you try sending the request via Zuul at: http://<zuul host>:<zuul port>/<zuul app context>/api/test/.... ?

Feign Client ignoring request params

I created Feign Client:
#FeignClient(name = "yandex",url="${yandex.ribbon.listOfServers}")
public interface YandexMapsRestApiServiceClient {
#RequestMapping(method = RequestMethod.GET, value = "{geoParam}")
String getCountryInfo(#Param("geoParam") String geoParam);
}
In controller I have been wrote:
#Autowired
private YandexMapsRestApiServiceClient client;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String test() {
return client.getCountryInfo("Moscow");
}
My Applicaton.yml look this:
yandex:
ribbon:
listOfServers: https://geocode-maps.yandex.ru/1.x/?format=json&geocode=
ConnectTimeout: 20000
ReadTimeout: 20000
IsSecure: true
hystrix.command.default.execution:
timeout.enabled: true
isolation.thread.timeoutInMilliseconds: 50000
When I try to get some result, in return I get 404 error:
feign.FeignException: status 404 reading YandexMapsRestApiServiceClient#getCountryInfo(String); content:
In this case, I see in the debugger that he feign not set my geoParam:
Why does this happen and how to solve this problem?
As Musaddique has stated, you are mixing Feign and Spring annotations. When using Spring Cloud Feign(OpenFeign), you must use the Spring annotation RequestParam. Feign annotations will not be processed.
Update
To achieve what you are looking for, you will need to change your configuration. The of url should be a url or service name only. Using query string or other extensions to the url will have unexpected results.
Move the path information to the RequestMapping annotation and specify the query parameter there.
#FeignClient(name = "yandex", url="${yandex.ribbon.listOfServers}")
public interface YandexMapsRestApiServiceClient {
#RequestMapping(method = RequestMethod.GET, value = "/1.x?format=json&geocode={geoParam}")
String getCountryInfo(#RequestParam("geoParam") String geoParam);
}
Where your ribbon configuration looks like this:
yandex:
ribbon:
listOfServers: "https://geocode-maps.yandex.ru"
ConnectTimeout: 20000
ReadTimeout: 20000
IsSecure: true
Now, using your example of client.getCountryInfo("moscow") will result in the final url of https://geocode-maps.yandex.ru/1.x?format=json&geocode=moscow.

Resources