On making a GET Request which returns a ModelAndView Object I am getting the following error
: GET "/tweet2?email=tim#gmail.com", parameters={masked} 2022-03-08
11:04:45.459 DEBUG 46576 --- [nio-8080-exec-3]
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to
com.example.demo.RestAPIExample#getTweetsByEmail(String) 2022-03-08
11:04:45.464 DEBUG 46576 --- [nio-8080-exec-3]
o.s.w.s.v.ContentNegotiatingViewResolver : Selected '/' given [/]
2022-03-08 11:04:45.464 DEBUG 46576 --- [nio-8080-exec-3]
o.s.w.servlet.view.InternalResourceView : View name 'tweets', model
{tweets=[com.example.demo.Tweet#3a7a85cb]} 2022-03-08 11:04:45.465
DEBUG 46576 --- [nio-8080-exec-3]
o.s.w.servlet.view.InternalResourceView : Forwarding to [tweets]
2022-03-08 11:04:45.467 DEBUG 46576 --- [nio-8080-exec-3]
o.s.web.servlet.DispatcherServlet : "FORWARD" dispatch for GET
"/tweets?email=tim#gmail.com", parameters={masked} 2022-03-08
11:04:45.470 DEBUG 46576 --- [nio-8080-exec-3]
o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped to
ResourceHttpRequestHandler [classpath [META-INF/resources/], classpath
[resources/], classpath [static/], classpath [public/], ServletContext
[/]] 2022-03-08 11:04:45.472 DEBUG 46576 --- [nio-8080-exec-3]
o.s.w.s.r.ResourceHttpRequestHandler : Resource not found
2022-03-08 11:04:45.473 DEBUG 46576 --- [nio-8080-exec-3]
o.s.web.servlet.DispatcherServlet : Exiting from "FORWARD"
dispatch, status 404 2022-03-08 11:04:45.473 DEBUG 46576 ---
[nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : Completed
404 NOT_FOUND 2022-03-08 11:04:45.474 DEBUG 46576 ---
[nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : "ERROR"
dispatch for GET "/error?email=tim#gmail.com", parameters={masked}
2022-03-08 11:04:45.475 DEBUG 46576 --- [nio-8080-exec-3]
s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to
org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
2022-03-08 11:04:45.482 DEBUG 46576 --- [nio-8080-exec-3]
o.s.w.s.m.m.a.HttpEntityMethodProcessor : Using 'application/json',
given [/] and supported [application/json, application/+json,
application/json, application/+json] 2022-03-08 11:04:45.483 DEBUG
46576 --- [nio-8080-exec-3] o.s.w.s.m.m.a.HttpEntityMethodProcessor :
Writing [{timestamp=Tue Mar 08 11:04:45 IST 2022, status=404,
error=Not Found, path=/tweet2}] 2022-03-08 11:04:45.497 DEBUG 46576
--- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet : Exiting from "ERROR" dispatch, status 404
Here is the code I wrote:
#GetMapping("/tweet2")
public ModelAndView getTweetsByEmail(#RequestParam String email) {
ModelAndView modelAndView = new ModelAndView("tweets");
List<Tweet> tweets = tweetMap.get(email);
modelAndView.getModel().put("tweets",tweets);
return modelAndView;
}
And there is a tweets.mustache file under the resources folder. Not sure why its unable to detect it
I'm building a microservices app and I've run into problem with configuring the Spring Cloud gateway to proxy the calls to the API from frontend running on Nginx server.
When I make a POST request to /users/login, I get this response: OPTIONS http://28a41511677e:8082/login net::ERR_NAME_NOT_RESOLVED.
The string 28a41511677e is the services docker container ID. When I call another service (using GET method), it returns data just fine.
I'm using Eureka discovery server which seems to find all the services correctly. The service in question is registered as 28a41511677e:users-service:8082
Docker compose:
version: "3.7"
services:
db:
build: db/
expose:
- 5432
registry:
build: registryservice/
expose:
- 8761
ports:
- 8761:8761
gateway:
build: gatewayservice/
expose:
- 8080
depends_on:
- registry
users:
build: usersservice/
expose:
- 8082
depends_on:
- registry
- db
timetable:
build: timetableservice/
expose:
- 8081
depends_on:
- registry
- db
ui:
build: frontend/
expose:
- 80
ports:
- 80:80
depends_on:
- gateway
Gateway implementation:
#EnableDiscoveryClient
#SpringBootApplication
public class GatewayserviceApplication {
#Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder){
return builder.routes()
.route("users-service", p -> p.path("/user/**")
.uri("lb://users-service"))
.route("timetable-service", p -> p.path("/routes/**")
.uri("lb://timetable-service"))
.build();
}
public static void main(String[] args) {
SpringApplication.run(GatewayserviceApplication.class, args);
}
}
Gateway settings:
spring:
application:
name: gateway-service
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
allowedOrigins: "*"
allowedMethods:
- GET
- POST
- PUT
- DELETE
eureka:
client:
service-url:
defaultZone: http://registry:8761/eureka
Users service controller:
#RestController
#CrossOrigin
#RequestMapping("/user")
public class UserController {
private UserService userService;
#Autowired
public UserController(UserService userService) {
this.userService = userService;
}
#PostMapping(path = "/login")
ResponseEntity<Long> login(#RequestBody LoginDto loginDto) {
logger.info("Logging in user");
Long uid = userService.logIn(loginDto);
return new ResponseEntity<>(uid, HttpStatus.OK);
}
}
Edit:
This also happens on NPM dev server. I tried changing the lb://users-service to http://users:8082, with no success, still getting ERR_NAME_NOT_RESOLVED.
I however found that when I call the endpoint, the following output can be seen in log:
gateway_1 | 2019-05-19 23:55:10.842 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Disable delta property : false
gateway_1 | 2019-05-19 23:55:10.866 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Single vip registry refresh property : null
gateway_1 | 2019-05-19 23:55:10.867 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Force full registry fetch : false
gateway_1 | 2019-05-19 23:55:10.868 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Application is null : false
gateway_1 | 2019-05-19 23:55:10.868 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Registered Applications size is zero : true
gateway_1 | 2019-05-19 23:55:10.869 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Application version is -1: false
gateway_1 | 2019-05-19 23:55:10.871 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Getting all instance registry info from the eureka server
gateway_1 | 2019-05-19 23:55:11.762 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : The response status is 200
users_1 | 2019-05-19 21:55:19.268 INFO 1 --- [nio-8082-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
users_1 | 2019-05-19 21:55:19.273 INFO 1 --- [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
users_1 | 2019-05-19 21:55:19.513 INFO 1 --- [nio-8082-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 239 ms
users_1 | 2019-05-19 21:55:20.563 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Disable delta property : false
users_1 | 2019-05-19 21:55:20.565 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Single vip registry refresh property : null
users_1 | 2019-05-19 21:55:20.565 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Force full registry fetch : false
users_1 | 2019-05-19 21:55:20.566 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Application is null : false
users_1 | 2019-05-19 21:55:20.566 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Registered Applications size is zero : true
users_1 | 2019-05-19 21:55:20.566 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Application version is -1: false
users_1 | 2019-05-19 21:55:20.567 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : Getting all instance registry info from the eureka server
users_1 | 2019-05-19 21:55:20.958 INFO 1 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient : The response status is 200
Edit 2:
I enabled logging for the gateway service and this is the output whenever I call /user/login. According to the logs, the gateway matches the /users/login/ correctly, but then starts using just /login for some reason.
2019-05-20 12:58:47.002 DEBUG 1 --- [or-http-epoll-2] r.n.http.server.HttpServerOperations : [id: 0xff6d8305, L:/172.19.0.4:8080 - R:/172.19.0.7:42958] New http connection, requesting read
2019-05-20 12:58:47.025 DEBUG 1 --- [or-http-epoll-2] reactor.netty.channel.BootstrapHandlers : [id: 0xff6d8305, L:/172.19.0.4:8080 - R:/172.19.0.7:42958] Initialized pipeline DefaultChannelPipeline{(BootstrapHandlers$BootstrapInitializerHandler#0 = reactor.netty.channel.BootstrapHandlers$BootstrapInitializerHandler), (reactor.left.httpCodec = io.netty.handler.codec.http.HttpServerCodec), (reactor.left.httpTrafficHandler = reactor.netty.http.server.HttpTrafficHandler), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)}
2019-05-20 12:58:47.213 DEBUG 1 --- [or-http-epoll-2] r.n.http.server.HttpServerOperations : [id: 0xff6d8305, L:/172.19.0.4:8080 - R:/172.19.0.7:42958] Increasing pending responses, now 1
2019-05-20 12:58:47.242 DEBUG 1 --- [or-http-epoll-2] reactor.netty.http.server.HttpServer : [id: 0xff6d8305, L:/172.19.0.4:8080 - R:/172.19.0.7:42958] Handler is being applied: org.springframework.http.server.reactive.ReactorHttpHandlerAdapter#575e590e
2019-05-20 12:58:47.379 TRACE 1 --- [or-http-epoll-2] o.s.c.g.f.WeightCalculatorWebFilter : Weights attr: {}
2019-05-20 12:58:47.817 DEBUG 1 --- [or-http-epoll-2] o.s.c.g.r.RouteDefinitionRouteLocator : RouteDefinition CompositeDiscoveryClient_USERS-SERVICE applying {pattern=/USERS-SERVICE/**} to Path
2019-05-20 12:58:47.952 DEBUG 1 --- [or-http-epoll-2] o.s.c.g.r.RouteDefinitionRouteLocator : RouteDefinition CompositeDiscoveryClient_USERS-SERVICE applying filter {regexp=/USERS-SERVICE/(?<remaining>.*), replacement=/${remaining}} to RewritePath
2019-05-20 12:58:47.960 DEBUG 1 --- [or-http-epoll-2] o.s.c.g.r.RouteDefinitionRouteLocator : RouteDefinition matched: CompositeDiscoveryClient_USERS-SERVICE
2019-05-20 12:58:47.961 DEBUG 1 --- [or-http-epoll-2] o.s.c.g.r.RouteDefinitionRouteLocator : RouteDefinition CompositeDiscoveryClient_GATEWAY-SERVICE applying {pattern=/GATEWAY-SERVICE/**} to Path
2019-05-20 12:58:47.964 DEBUG 1 --- [or-http-epoll-2] o.s.c.g.r.RouteDefinitionRouteLocator : RouteDefinition CompositeDiscoveryClient_GATEWAY-SERVICE applying filter {regexp=/GATEWAY-SERVICE/(?<remaining>.*), replacement=/${remaining}} to RewritePath
2019-05-20 12:58:47.968 DEBUG 1 --- [or-http-epoll-2] o.s.c.g.r.RouteDefinitionRouteLocator : RouteDefinition matched: CompositeDiscoveryClient_GATEWAY-SERVICE
2019-05-20 12:58:47.979 TRACE 1 --- [or-http-epoll-2] o.s.c.g.h.p.RoutePredicateFactory : Pattern "/user/**" matches against value "/user/login"
2019-05-20 12:58:47.980 DEBUG 1 --- [or-http-epoll-2] o.s.c.g.h.RoutePredicateHandlerMapping : Route matched: users-service
2019-05-20 12:58:47.981 DEBUG 1 --- [or-http-epoll-2] o.s.c.g.h.RoutePredicateHandlerMapping : Mapping [Exchange: POST http://gateway:8080/user/login] to Route{id='users-service', uri=lb://users-service, order=0, predicate=org.springframework.cloud.gateway.support.ServerWebExchangeUtils$$Lambda$333/0x000000084035ac40#276b060f, gatewayFilters=[]}
2019-05-20 12:58:47.981 DEBUG 1 --- [or-http-epoll-2] o.s.c.g.h.RoutePredicateHandlerMapping : [ff6d8305] Mapped to org.springframework.cloud.gateway.handler.FilteringWebHandler#4faea64b
2019-05-20 12:58:47.994 DEBUG 1 --- [or-http-epoll-2] o.s.c.g.handler.FilteringWebHandler : Sorted gatewayFilterFactories: [OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter#773f7880}, order=-2147482648}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.NettyWriteResponseFilter#65a4798f}, order=-1}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.ForwardPathFilter#4c51bb7}, order=0}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter#878452d}, order=10000}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.LoadBalancerClientFilter#4f2613d1}, order=10100}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.WebsocketRoutingFilter#83298d7}, order=2147483646}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.NettyRoutingFilter#6d24ffa1}, order=2147483647}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.ForwardRoutingFilter#426b6a74}, order=2147483647}]
2019-05-20 12:58:47.996 TRACE 1 --- [or-http-epoll-2] o.s.c.g.filter.RouteToRequestUrlFilter : RouteToRequestUrlFilter start
2019-05-20 12:58:47.999 TRACE 1 --- [or-http-epoll-2] o.s.c.g.filter.LoadBalancerClientFilter : LoadBalancerClientFilter url before: lb://users-service/user/login
2019-05-20 12:58:48.432 INFO 1 --- [or-http-epoll-2] c.netflix.config.ChainedDynamicProperty : Flipping property: users-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2019-05-20 12:58:48.492 INFO 1 --- [or-http-epoll-2] c.n.u.concurrent.ShutdownEnabledTimer : Shutdown hook installed for: NFLoadBalancer-PingTimer-users-service
2019-05-20 12:58:48.496 INFO 1 --- [or-http-epoll-2] c.netflix.loadbalancer.BaseLoadBalancer : Client: users-service instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=users-service,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2019-05-20 12:58:48.506 INFO 1 --- [or-http-epoll-2] c.n.l.DynamicServerListLoadBalancer : Using serverListUpdater PollingServerListUpdater
2019-05-20 12:58:48.543 INFO 1 --- [or-http-epoll-2] c.netflix.config.ChainedDynamicProperty : Flipping property: users-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2019-05-20 12:58:48.555 INFO 1 --- [or-http-epoll-2] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client users-service initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=users-service,current list of Servers=[157e1f567371:8082],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:1; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]
},Server stats: [[Server:157e1f567371:8082; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 01:00:00 CET 1970; First connection made: Thu Jan 01 01:00:00 CET 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList#3cd9b0bf
2019-05-20 12:58:48.580 TRACE 1 --- [or-http-epoll-2] o.s.c.g.filter.LoadBalancerClientFilter : LoadBalancerClientFilter url chosen: http://157e1f567371:8082/user/login
2019-05-20 12:58:48.632 DEBUG 1 --- [or-http-epoll-2] r.n.resources.PooledConnectionProvider : Creating new client pool [proxy] for 157e1f567371:8082
2019-05-20 12:58:48.646 DEBUG 1 --- [or-http-epoll-2] r.n.resources.PooledConnectionProvider : [id: 0xa9634439] Created new pooled channel, now 0 active connections and 1 inactive connections
2019-05-20 12:58:48.651 DEBUG 1 --- [or-http-epoll-2] reactor.netty.channel.BootstrapHandlers : [id: 0xa9634439] Initialized pipeline DefaultChannelPipeline{(BootstrapHandlers$BootstrapInitializerHandler#0 = reactor.netty.channel.BootstrapHandlers$BootstrapInitializerHandler), (SimpleChannelPool$1#0 = io.netty.channel.pool.SimpleChannelPool$1), (reactor.left.httpCodec = io.netty.handler.codec.http.HttpClientCodec), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)}
2019-05-20 12:58:48.673 DEBUG 1 --- [or-http-epoll-2] r.n.resources.PooledConnectionProvider : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] onStateChange(PooledConnection{channel=[id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082]}, [connected])
2019-05-20 12:58:48.679 DEBUG 1 --- [or-http-epoll-2] r.n.resources.PooledConnectionProvider : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] onStateChange(GET{uri=/, connection=PooledConnection{channel=[id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082]}}, [configured])
2019-05-20 12:58:48.682 DEBUG 1 --- [or-http-epoll-2] r.n.resources.PooledConnectionProvider : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] Registering pool release on close event for channel
2019-05-20 12:58:48.690 DEBUG 1 --- [or-http-epoll-2] r.netty.http.client.HttpClientConnect : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] Handler is being applied: {uri=http://157e1f567371:8082/user/login, method=POST}
2019-05-20 12:58:48.701 DEBUG 1 --- [or-http-epoll-2] r.n.channel.ChannelOperationsHandler : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] New sending options
2019-05-20 12:58:48.720 DEBUG 1 --- [or-http-epoll-2] r.n.channel.ChannelOperationsHandler : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] Writing object DefaultHttpRequest(decodeResult: success, version: HTTP/1.1)
POST /user/login HTTP/1.1
content-length: 37
accept-language: cs-CZ,cs;q=0.9,en;q=0.8
referer: http://localhost/user/login
cookie: JSESSIONID=6797219EB79F6026BD8F19E9C46C09DB
accept: application/json, text/plain, */*
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36
content-type: application/json;charset=UTF-8
origin: http://gateway:8080
accept-encoding: gzip, deflate, br
Forwarded: proto=http;host="gateway:8080";for="172.19.0.7:42958"
X-Forwarded-For: 172.19.0.1,172.19.0.7
X-Forwarded-Proto: http,http
X-Forwarded-Port: 80,8080
X-Forwarded-Host: localhost,gateway:8080
host: 157e1f567371:8082
2019-05-20 12:58:48.751 DEBUG 1 --- [or-http-epoll-2] r.n.resources.PooledConnectionProvider : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] Channel connected, now 1 active connections and 0 inactive connections
2019-05-20 12:58:48.759 DEBUG 1 --- [or-http-epoll-2] r.n.channel.ChannelOperationsHandler : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] Writing object
2019-05-20 12:58:48.762 DEBUG 1 --- [or-http-epoll-2] reactor.netty.channel.FluxReceive : [id: 0xff6d8305, L:/172.19.0.4:8080 - R:/172.19.0.7:42958] Subscribing inbound receiver [pending: 1, cancelled:false, inboundDone: true]
2019-05-20 12:58:48.808 DEBUG 1 --- [or-http-epoll-2] r.n.channel.ChannelOperationsHandler : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] Writing object EmptyLastHttpContent
2019-05-20 12:58:48.809 DEBUG 1 --- [or-http-epoll-2] r.n.resources.PooledConnectionProvider : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] onStateChange(POST{uri=/user/login, connection=PooledConnection{channel=[id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082]}}, [request_sent])
2019-05-20 12:58:49.509 INFO 1 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty : Flipping property: users-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2019-05-20 12:58:49.579 DEBUG 1 --- [or-http-epoll-2] r.n.http.client.HttpClientOperations : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] Received response (auto-read:false) : [Set-Cookie=JSESSIONID=7C47A99C1F416F910AB554F4617247D6; Path=/; HttpOnly, X-Content-Type-Options=nosniff, X-XSS-Protection=1; mode=block, Cache-Control=no-cache, no-store, max-age=0, must-revalidate, Pragma=no-cache, Expires=0, X-Frame-Options=DENY, Location=http://157e1f567371:8082/login, Content-Length=0, Date=Mon, 20 May 2019 10:58:49 GMT]
2019-05-20 12:58:49.579 DEBUG 1 --- [or-http-epoll-2] r.n.resources.PooledConnectionProvider : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] onStateChange(POST{uri=/user/login, connection=PooledConnection{channel=[id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082]}}, [response_received])
2019-05-20 12:58:49.581 TRACE 1 --- [or-http-epoll-2] o.s.c.g.filter.NettyWriteResponseFilter : NettyWriteResponseFilter start
2019-05-20 12:58:49.586 DEBUG 1 --- [or-http-epoll-2] reactor.netty.channel.FluxReceive : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] Subscribing inbound receiver [pending: 0, cancelled:false, inboundDone: false]
2019-05-20 12:58:49.586 DEBUG 1 --- [or-http-epoll-2] r.n.http.client.HttpClientOperations : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] Received last HTTP packet
2019-05-20 12:58:49.593 DEBUG 1 --- [or-http-epoll-2] r.n.channel.ChannelOperationsHandler : [id: 0xff6d8305, L:/172.19.0.4:8080 - R:/172.19.0.7:42958] Writing object DefaultFullHttpResponse(decodeResult: success, version: HTTP/1.1, content: EmptyByteBufBE)
HTTP/1.1 302 Found
Set-Cookie: JSESSIONID=7C47A99C1F416F910AB554F4617247D6; Path=/; HttpOnly
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Location: http://157e1f567371:8082/login
Date: Mon, 20 May 2019 10:58:49 GMT
content-length: 0
2019-05-20 12:58:49.595 DEBUG 1 --- [or-http-epoll-2] r.n.http.server.HttpServerOperations : [id: 0xff6d8305, L:/172.19.0.4:8080 - R:/172.19.0.7:42958] Detected non persistent http connection, preparing to close
2019-05-20 12:58:49.595 DEBUG 1 --- [or-http-epoll-2] r.n.http.server.HttpServerOperations : [id: 0xff6d8305, L:/172.19.0.4:8080 - R:/172.19.0.7:42958] Last Http packet was sent, terminating channel
2019-05-20 12:58:49.598 DEBUG 1 --- [or-http-epoll-2] r.n.resources.PooledConnectionProvider : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] onStateChange(POST{uri=/user/login, connection=PooledConnection{channel=[id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082]}}, [disconnecting])
2019-05-20 12:58:49.598 DEBUG 1 --- [or-http-epoll-2] r.n.resources.PooledConnectionProvider : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] Releasing channel
2019-05-20 12:58:49.598 DEBUG 1 --- [or-http-epoll-2] r.n.resources.PooledConnectionProvider : [id: 0xa9634439, L:/172.19.0.4:59624 - R:157e1f567371/172.19.0.5:8082] Channel cleaned, now 0 active connections and 1 inactive connections
I managed to fix it. The problem was actually not in the gateway, it was in the users service. It had improper security configuration and required a login when accessing its endpoints. So, when I called any endpoint, it got redirected to /login.
I added the following code to the service and it works properly now.
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.authorizeRequests().antMatchers("/").permitAll();
httpSecurity.cors().and().csrf().disable();
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
That's probably not a proper solution, but on a non production code it gets the job done.
A sample project is located here: https://github.com/codependent/spring5-playground
I would like to bridge a message received from a JMS queue into a Reactive Controller that would publish the messages as an event stream.
I don't want the messages to be replayed, that is, if a message arrives and there isn't any subscriber I don't want them to be sent later when any subsbribes, so I am using an EmitterProcessor:
#Component
public class AlertEmitterProcessor {
private Logger logger = LoggerFactory.getLogger(getClass());
private EmitterProcessor<Alert> processor;
public AlertEmitterProcessor(){
processor = EmitterProcessor.<Alert>create();
processor.connect();
}
public EmitterProcessor<Alert> getProcessor() {
return processor;
}
public void onNext(Alert alert){
logger.info("onNext [{}]", alert);
processor.onNext(alert);
}
public void onComplete(){
logger.info("onComplete");
processor.onComplete();
}
public void onError(Throwable t){
logger.error("onError", t);
processor.onError(t);
}
}
This is my MessageListener:
#Component
public class AlertMessageListener implements MessageListener{
private Logger logger = LoggerFactory.getLogger(getClass());
#Autowired
private AlertEmitterProcessor alertProcessor;
#Autowired
private MappingJackson2HttpMessageConverter jacksonMessageConverter;
#Override
public void onMessage(Message message) {
logger.info("Message received: [{}]", message);
TextMessage tm = (TextMessage)message;
try {
Alert alert = jacksonMessageConverter.getObjectMapper().readValue(tm.getText(), Alert.class);
alertProcessor.onNext(alert);
} catch (IOException | JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
And finally my Rest Controller:
#Autowired
private AlertEmitterProcessor alertTopicProcessor;
#Autowired
private AlertMessageListener messageListener;
#Autowired
private MappingJackson2HttpMessageConverter jacksonMessageConverter;
#GetMapping(value="/accounts/{id}/alerts/live2", produces="text/event-stream")
public Flux<Alert> getAccountAlertsStreaming2(#PathVariable Integer id) {
return alertTopicProcessor.getProcessor()
.log().filter( a -> a.getAccountId().equals(id) );
}
To test its behaviour I have added this controller method to simulate inserting in the queue:
#GetMapping(value="/mock/accounts/{id}/alerts/put", produces="text/event-stream")
public void putAlert(#PathVariable Integer id) throws JsonProcessingException {
Alert alert = new Alert(id, (long)Math.round(Math.random()*10), "Message");
String alertStr = jacksonMessageConverter.getObjectMapper().writeValueAsString(alert);
TextMessage tm = new MockTextMessage(alertStr);
messageListener.onMessage(tm);
}
Right after starting the application I load http://localhost:8080/accounts/1/alerts/live2 and the browser waits for data.
2016-10-03 13:43:38.755 DEBUG 12800 --- [nio-8080-exec-1] o.s.web.reactive.DispatcherHandler : Processing GET request for [http://localhost:8080/accounts/1/alerts/live2]
2016-10-03 13:43:38.770 DEBUG 12800 --- [nio-8080-exec-1] s.w.r.r.m.a.RequestMappingHandlerMapping : Looking up handler method for path /accounts/1/alerts/live2
2016-10-03 13:43:38.778 DEBUG 12800 --- [nio-8080-exec-1] s.w.r.r.m.a.RequestMappingHandlerMapping : Returning handler method [public reactor.core.publisher.Flux<com.codependent.spring5.playground.reactive.dto.Alert> com.codependent.spring5.playground.reactive.web.AccountsRestController.getAccountAlertsStreaming2(java.lang.Integer)]
2016-10-03 13:43:38.779 DEBUG 12800 --- [nio-8080-exec-1] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'accountsRestController'
2016-10-03 13:43:38.800 INFO 12800 --- [nio-8080-exec-1] reactor.unresolved : onSubscribe(reactor.core.publisher.FluxPeek$PeekSubscriber#54d4fb36)
2016-10-03 13:43:38.802 INFO 12800 --- [nio-8080-exec-1] reactor.unresolved : request(unbounded)
2016-10-03 13:43:38.803 INFO 12800 --- [nio-8080-exec-1] reactor.unresolved : onNext(1)
2016-10-03 13:43:38.822 INFO 12800 --- [nio-8080-exec-1] reactor.Flux.EmitterProcessor.2 : onSubscribe(reactor.core.publisher.EmitterProcessor$EmitterSubscriber#227405f2)
2016-10-03 13:43:38.822 INFO 12800 --- [nio-8080-exec-1] reactor.Flux.EmitterProcessor.2 : request(1)
2016-10-03 13:43:38.823 INFO 12800 --- [nio-8080-exec-1] reactor.unresolved : onComplete()
Then I publish some messages http://localhost:8080/mock/accounts/1/alerts/put.
2016-10-03 13:43:43.063 DEBUG 12800 --- [nio-8080-exec-2] o.s.web.reactive.DispatcherHandler : Processing GET request for [http://localhost:8080/mock/accounts/1/alerts/put]
2016-10-03 13:43:43.063 DEBUG 12800 --- [nio-8080-exec-2] s.w.r.r.m.a.RequestMappingHandlerMapping : Looking up handler method for path /mock/accounts/1/alerts/put
2016-10-03 13:43:43.068 DEBUG 12800 --- [nio-8080-exec-2] s.w.r.r.m.a.RequestMappingHandlerMapping : Returning handler method [public void com.codependent.spring5.playground.reactive.web.AccountsRestController.putAlert(java.lang.Integer) throws com.fasterxml.jackson.core.JsonProcessingException]
2016-10-03 13:43:43.069 DEBUG 12800 --- [nio-8080-exec-2] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'accountsRestController'
2016-10-03 13:43:43.071 INFO 12800 --- [nio-8080-exec-2] reactor.unresolved : onSubscribe(reactor.core.publisher.FluxPeek$PeekSubscriber#2ba7d09c)
2016-10-03 13:43:43.071 INFO 12800 --- [nio-8080-exec-2] reactor.unresolved : request(unbounded)
2016-10-03 13:43:43.072 INFO 12800 --- [nio-8080-exec-2] reactor.unresolved : onNext(1)
2016-10-03 13:43:43.112 INFO 12800 --- [nio-8080-exec-2] c.c.s.p.r.message.AlertMessageListener : Message received: [com.codependent.spring5.playground.reactive.message.MockTextMessage#37262c9e]
2016-10-03 13:43:43.145 INFO 12800 --- [nio-8080-exec-2] c.c.s.p.r.message.AlertEmitterProcessor : onNext [Alert [alertId=3, message=Message, accountId=1]]
2016-10-03 13:43:43.146 INFO 12800 --- [nio-8080-exec-2] reactor.Flux.EmitterProcessor.2 : onNext(Alert [alertId=3, message=Message, accountId=1])
2016-10-03 13:43:43.177 INFO 12800 --- [nio-8080-exec-2] reactor.unresolved : onComplete()
2016-10-03 13:43:43.177 DEBUG 12800 --- [nio-8080-exec-2] o.s.h.s.r.ServletHttpHandlerAdapter : Successfully completed request
But none get to the browser. This eventyally finishes with a 500 error (no log).
After some manual retries it starts receiving data...
2016-10-03 13:45:07.726 DEBUG 12800 --- [nio-8080-exec-8] s.w.r.r.m.a.RequestMappingHandlerMapping : Returning handler method [public reactor.core.publisher.Flux<com.codependent.spring5.playground.reactive.dto.Alert> com.codependent.spring5.playground.reactive.web.AccountsRestController.getAccountAlertsStreaming2(java.lang.Integer)]
2016-10-03 13:45:07.726 DEBUG 12800 --- [nio-8080-exec-8] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'accountsRestController'
2016-10-03 13:45:07.727 INFO 12800 --- [nio-8080-exec-8] reactor.unresolved : onSubscribe(reactor.core.publisher.FluxPeek$PeekSubscriber#909f06f)
2016-10-03 13:45:07.727 INFO 12800 --- [nio-8080-exec-8] reactor.unresolved : request(unbounded)
2016-10-03 13:45:07.727 INFO 12800 --- [nio-8080-exec-8] reactor.unresolved : onNext(1)
2016-10-03 13:45:07.729 INFO 12800 --- [nio-8080-exec-8] reactor.Flux.EmitterProcessor.9 : onSubscribe(reactor.core.publisher.EmitterProcessor$EmitterSubscriber#7ce1f3e)
2016-10-03 13:45:07.729 INFO 12800 --- [nio-8080-exec-8] reactor.Flux.EmitterProcessor.9 : request(1)
2016-10-03 13:45:07.729 INFO 12800 --- [nio-8080-exec-8] reactor.Flux.EmitterProcessor.9 : onNext(Alert [alertId=4, message=Message, accountId=1])
2016-10-03 13:45:07.730 INFO 12800 --- [nio-8080-exec-8] reactor.unresolved : onComplete()
2016-10-03 13:45:07.747 INFO 12800 --- [nio-8080-exec-8] reactor.Flux.EmitterProcessor.9 : request(1)
2016-10-03 13:45:07.747 INFO 12800 --- [nio-8080-exec-8] reactor.Flux.EmitterProcessor.9 : onNext(Alert [alertId=0, message=Message, accountId=1])
2016-10-03 13:45:07.748 INFO 12800 --- [nio-8080-exec-8] reactor.Flux.EmitterProcessor.9 : request(1)
... but many other times it doesn't get any.
It was resolved in Spring 5 M3:
https://jira.spring.io/browse/SPR-14803
https://jira.spring.io/browse/SPR-14772
I create a spring-boot app with #EnableSidecar and I see that a route for the registered eureka clients "offers" and "customers" is created (Mapped URL path [/customers/**] onto ...) and the routes show up on the http://localhost:9000/routes endpoint:
{
"_links":{
"self":{
"href":"http://localhost:8090/routes"
}
},
"/customers/**":"customers",
"/zuul-proxy/**":"zuul-proxy",
"/offers/**":"offers"
}
When accessing http://localhost:9000/customers on the zuul-proxy in the browser I get a 404 thought.
My application.yml
spring:
application:
name: zuul-proxy
server:
port: 9000
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
ZuulProxyApplication.java:
#EnableSidecar
#SpringBootApplication
public class ZuulProxyApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulProxyApplication.class, args);
}
}
Log output:
2015-09-11 23:33:09.236 INFO 42750 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8090 (http)
2015-09-11 23:33:09.237 INFO 42750 --- [ main] c.n.e.EurekaDiscoveryClientConfiguration : Registering application zuul-proxy with eureka with status UP
2015-09-11 23:33:09.238 INFO 42750 --- [ main] com.netflix.discovery.DiscoveryClient : Saw local status change event StatusChangeEvent [current=UP, previous=STARTING]
2015-09-11 23:33:09.241 INFO 42750 --- [ main] o.s.c.n.zuul.web.ZuulHandlerMapping : Mapped URL path [/customers/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
2015-09-11 23:33:09.242 INFO 42750 --- [ main] o.s.c.n.zuul.web.ZuulHandlerMapping : Mapped URL path [/offers/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
2015-09-11 23:33:09.245 INFO 42750 --- [ main] ch.local.zuul.ZuulProxyApplication : Started ZuulProxyApplication in 8.637 seconds (JVM running for 9.26)
2015-09-11 23:33:09.245 INFO 42750 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_ZUUL-PROXY/192.168.0.108: registering service...
2015-09-11 23:33:09.294 INFO 42750 --- [nfoReplicator-0] com.netflix.discovery.DiscoveryClient : DiscoveryClient_ZUUL-PROXY/192.168.0.108 - registration status: 204
2015-09-11 23:33:14.545 INFO 42750 --- [nio-8090-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'
2015-09-11 23:33:14.545 INFO 42750 --- [nio-8090-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started
2015-09-11 23:33:14.572 INFO 42750 --- [nio-8090-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 27 ms
2015-09-11 23:33:14.616 INFO 42750 --- [nio-8090-exec-1] o.s.c.n.zuul.filters.ProxyRouteLocator : Finding route for path: /customers
2015-09-11 23:33:14.626 INFO 42750 --- [nio-8090-exec-1] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext#7442808: startup date [Fri Sep 11 23:33:14 CEST 2015]; parent: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#3a60c416
2015-09-11 23:33:14.646 INFO 42750 --- [nio-8090-exec-1] f.a.AutowiredAnnotationBeanPostProcessor : JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
2015-09-11 23:33:14.759 INFO 42750 --- [nio-8090-exec-1] c.netflix.config.ChainedDynamicProperty : Flipping property: customers.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2015-09-11 23:33:14.802 INFO 42750 --- [nio-8090-exec-1] c.n.u.concurrent.ShutdownEnabledTimer : Shutdown hook installed for: NFLoadBalancer-PingTimer-customers
2015-09-11 23:33:14.829 INFO 42750 --- [nio-8090-exec-1] c.netflix.loadbalancer.BaseLoadBalancer : Client:customers instantiated a LoadBalancer:DynamicServerListLoadBalancer:{NFLoadBalancer:name=customers,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
2015-09-11 23:33:14.855 INFO 42750 --- [nio-8090-exec-1] c.netflix.config.ChainedDynamicProperty : Flipping property: customers.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2015-09-11 23:33:14.858 INFO 42750 --- [nio-8090-exec-1] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client customers initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=customers,current list of Servers=[192.168.0.108:customers - 8083, 192.168.0.108:customers - 8081],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:2; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]
},Server stats: [[Server:192.168.0.108:customers - 8081; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 01:00:00 CET 1970; First connection made: Thu Jan 01 01:00:00 CET 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
, [Server:192.168.0.108:customers - 8083; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 01:00:00 CET 1970; First connection made: Thu Jan 01 01:00:00 CET 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList#55d7aafe
2015-09-11 23:33:14.941 INFO 42750 --- [nio-8090-exec-1] com.netflix.http4.ConnectionPoolCleaner : Initializing ConnectionPoolCleaner for NFHttpClient:customers
2015-09-11 23:33:15.838 INFO 42750 --- [ool-10-thread-1] c.netflix.config.ChainedDynamicProperty : Flipping property: customers.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2015-09-11 23:33:19.287 INFO 42750 --- [nio-8090-exec-2] o.s.c.n.zuul.filters.ProxyRouteLocator : Finding route for path: /customers
2015-09-11 23:33:35.780 INFO 42750 --- [pool-3-thread-1] o.s.c.n.zuul.web.ZuulHandlerMapping : Mapped URL path [/zuul-proxy/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
I see the customers and offers instances registered in eureka. I also can access them via a RestTemplate in the zuul-proxy app like:
#RestController
public class TestController {
#Autowired
private RestTemplate restTemplate;
#RequestMapping("/test")
public Customer test() {
return restTemplate.getForObject("http://customers/customers/1", Customer.class);
}
}
This is working when I call http://localhost:9000/test
What could be the problem that I get a 404 for the registered routes http://localhost:9000/customers and http://localhost:9000/offers?