Spring Web: Mapping URL to a standalone Spring app - rest

I have two standalone Spring Boot/Web web app .jars, A and B, both made by third-parties, with their own URL mappings which I do not know about in advance.
I would like to create a setup where "localhost:8080/A" maps (passes through) to A's "/" mapping. Similarly, "localhost:8080/B" should pass through to B's "/" mapping.
Additional mappings, which again I don't necessarily know about in advance, should also pass through respectively - so "localhost:8080/A/items" should pass through to A's "/items", etc.
I do not have the source code for A or B, only .jar files.
For security, A and B should have separate scopes with no knowledge of each other or ability to interact with each other. The whole setup should behave as if A and B were separate "inner" servers within my "outer" localhost server.
Can this be achieved via a Spring Boot/Web wrapper or gateway app, or some other way?

You could use spring boot with Zuul as a third app, running on 8080, which has routes setup for A and B similar to what you described.
zuul:
routes:
app-A:
path: /A/**
url: http://localhost:8081/
app-B:
path: /B/**
url: http://localhost:8082/
That configuration (application.yml) of your third app would point "A" traffic to port 8081 and "B" traffic to port 8082.
This is quick and dirty, but should get you started.
Alternatively, you could use spring cloud gateway, to get a similar type of setup with the additional ability to do sockets/reactive.

Related

Is it possible to have a single frontend select between backends (defined dynamically)?

I am currently looking into deploying Traefik/Træfik on our service fabric cluster.
Basically I have a setup where I have any number of Applications (services), defined with a tenant name and each of these services is in fact a separate Web UI.
I am trying to figure out if I can configure a single frontend to target a backend so I don't have to define a new frontend each time I deploy a new UI app. Something like
[frontend.tenantui]
rule = "HostRegexp:localhost,{tenantName:[a-z]+}.example.com"
backend = "fabric:/WebApp/{tenantName}"
The idea is to have it such that I can just deploy new UI services without updating the frontend configuration.
I am currently using the Service Fabric provider for my backend services, but I am open to using the file provider or something else if that is required.
Update:
The servicemanifset contains labels, so as to let traefik create backends and frontends.
The labels are defined for one service, lets call it WebUI as an example. Now when I deploy an instance of WebUI it gets a label and traefik understands it.
Then I deploy ANOTHER instance with a DIFFERENT set of parameters, its still the WebUI service and it uses the same manifest, so it gets the same labels, and the same routing. But what I would really want was to let it have a label containing some sort of rule so I could route to the name of the service instance (determine at runtime not design time). Specifically I would like for the runtime part to be part of the domainname (thus the suggestion of a HostRegexp style rule)
I don't think it is possible to use the matched group from the HostRegexp to determine the backend.
A possibility would be to use the Property Manager API to dynamically set the frontend rule for the service instance after creating it. Also, see this for a complete example on using the API.

Cors and database uri problem in scaling out architecture

I have react frontend and spring boot backend with mongodb behind.
I have issues with setting 2 parameters in the spring boot service.
First is address of the mongodb which is now set as localhost:27017 in the application.properties
It works at localhost but since I plan to scale out using kubernetes and docker images i would like to know how to define
It and where for the case in which I have mongo1 mongo2 and mongo3 database hosts and would like to pass all 3 URIs ?
Second issues is more tricky! React frontend doesnt work in chrome until I put allow cross origin anotation over my spring rest endpoint . I used hardcoded localhost:3000 here but when I scale it out using kubernetes this wont work if it gets data from another host in the cluster.What to do here?
To answer your first question, you can configure multi data sources, see here documentation how you can configure more than one data sources (80.2 Configure Two DataSources.
For second question you can simply wildcard CORS URL or if you know all of your front end server urls which are load balanced you can pass as list of cors url.
– * – means that all origins are allowed.
– If undefined, all origins are allowed.
RECOMMENDATION
Run your react via yarn to deploy on Apache or ngnix. Once you seted up your domain or sub domain for front end, load balanced your front end so not required to run your front end on ports..

Is it possible to define a static server list with ribbon (via feign) when Eureka is in use?

Environment
Spring Boot 1.5.13.RELEASE
Spring Cloud Edgware.SR3
Java 8
Configuration
Eureka client is enabled and working correctly (I have tested and everything's working as I expect).
Some relevant properties from my configuration:
feign.hystrix.enabled=true
eureka.client.fetch-registry=true
spring.cloud.service-registry.auto-registration.enabled=true
service1.ribbon.listOfServers=https://www.google.com
Context
I have an application which speaks to 3 other services using feign clients. Two of these are discovered via Eureka service discovery. These are working well. The final service is an external one with a single static hostname and I do not want this resolved via Eureka. Since I do want Eureka for 2 of these services I would like to keep Eureka enabled.
Question
For the final service I tried adding service1.ribbon.listOfServers=https://www.google.com to the application.properties, however this cases the following error at runtime when invoking the feign client:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.netflix.hystrix.exception.HystrixRuntimeException: Service1Client#test() failed and no fallback available.] with root cause
pricing_1 |
pricing_1 | com.netflix.client.ClientException: Load balancer does not have available server for client: service1
pricing_1 | at com.netflix.loadbalancer.LoadBalancerContext.getServerFromLoadBalancer(LoadBalancerContext.java:483) ~[ribbon-loadbalancer-2.2.5.jar!/:2.2.5]
My client is configured as follows:
#FeignClient("service1")
public interface Service1Client {
#GetMapping(value = "/")
String test();
}
Thanks in advance for any advice.
Consideration
Since the spirit of Ribbon as I understand it is to act as a client side load balancer and given in my case there is nothing to load balance (I have one fixed static hostname that returns a single A record in DNS). Ribbon actually feels like an unnecessary component - what I really wanted was the Feign client as I like the fact that it abstracts away the lower level HTTP request and object seralization. So I suppose an alternative follow up question is, can I use feign without ribbon - it seems the nice out of the box behaviour would be to use ribbon - even the Javadoc of the #FeignClient annotation says:
If ribbon is available it will be
used to load balance the backend requests, and the load balancer can be configured
using a #RibbonClient with the same name (i.e. value) as the feign client.
suggesting the two are quite closely related even if they are serving different purposes.
As you mentioned, there are two ways to solve your problem.
Use Feign without Ribbon
If you specify url attribute in #FeignClient annotation, it will work without Ribbon like the below.
#FeignClient(name = "service1", url = http://www.google.com)
public interface Service1Client {
#GetMapping(value = "/")
String test();
}
In this case, your other two Feign client will still work with Ribbon and Eureka.
Use Feign with Ribbon and without Eureka
What you are missing is in your configuration is NIWSServerListClassName.
Its default value is com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList and it will use Eureka to retrieve the list of server. If you set NIWSServerListClassName to ConfigurationBasedServerList for a ribbon client (feign client), only that client will work with listOfServers list without retrieving server list from Eureka. And other feign clients will still work with Eureka.
service1:
ribbon:
NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
listOfServers: http://www.google.com

Zuul routing doesn't work, gives 404 : Spring Boot+ Cloud+ Zuul

I am working on a flow where I have ng4+boot app running on https://host_a:8080 and a backend service at https://host_b:8080 with some APIs.
I have RestController/Path at both the hosts, i.e. I need some urls to hit localhost (host_a) and others to host_b.
In application.yml, I have tried almost all possible combinations of Zuul routes but still getting 404 for all host_b rest APIs. host_a APIs work well.
Note: We have this working when there is no rest API on host_a and no custom filter on host_a.
Is there something wrong working with filter? I don't see any log from zuul filter now after I added this controller to host_a
I am aware that I can use forward property to route to localhost which works well. But somehow host_b rest all gives 404 error.
My implementation requirements-
http://host_a:8080/api/abc/user to hit at localhost i.e. host_a
http://host_a:8080/api/xyz/getall to hit at host_b
Important- Need a custom zuul filter which adds certain headers to request before it's routed to host_b as explained in point 2. - Already at place, but cannot see logs inside it now.
What I tried already-
zuul:
routes:
xyz:
path: /api/xyz/**
url: http://host_b:8080/api/xyz
I tried almost everything, using prefix, strip-prefix, only host in url, using forward for local routing, etc. Nothing works.
Kindly help me with the possible causes I may be ignoring or if missing something?
Thanks in advance.
Finally, I was able to resolve issues.
1. I had to change jersey #Path to spring #RestController
2. Changed Zuul Filter order from 1 to 999.
Works well now.

Context routing for two different apps

I deploy two different apps to CF and I want to be able to use the context path routing for those two apps
e.g.
lets say I've two apps that deployed and I was able to consume it with the following URL.
1. app1.domain.com
2. app2.domain.com
Now I want somehow to use the context path routing of CF
to be able to use this apps like following
1. something.domain.com/app1
2. something.domain.com/app2
My question are:
I missing the "something", what should I put in the apps manifest to be able to use it like above ?
How should I define the routes in the mainfest.yml file?
what should I put in the path?
Example will be very helpful
https://www.cloudfoundry.org/context-path-routing/
Lucky that I recently prepared a blog post and a tutorial on context path routing. Here is a sample manifest.yml taken from the tutorial that shows two apps with different routes on the same domain:
# This manifest deploys two applications.
#
# Both use the same host and domain name as defined
# by their respective route(s) property. The first app
# uses the root path, the second the "sub" and
# "lower" paths.
applications:
# The Python app starts here
- name: yourname-myapp
memory: 256M
command: python myapp.py
routes:
- route: yourname-myapp.mybluemix.net
path: ./top/
# The Node.js app starts here
- name: yourname-myapp-node
routes:
- route: yourname-myapp.mybluemix.net/lower
- route: yourname-myapp.mybluemix.net/sub
path: ./lower/
You can even define multiple routes for a single app, all in a single manifest file. The routes property is the place for the routing information. Note that the path points to the source code for the app (if done this way) and that you need a recent version of cf CLI to deploy it. See the tutorial for more information and additional links.
You can also find a good example in the map route documentation per below
https://docs.cloudfoundry.org/devguide/deploy-apps/routes-domains.html#map-route