Spring Cloud: default redirecting from Gateway to UI - spring

I'm new to microservices and Spring Boot. I have a few Spring Cloud microservices with a Zuul gateway running on port 8080.
browser
|
|
gateway (:8080)
/ \
/ \
/ \
resource UI (:8090)
There is a UI microservice on port 8090, which has a controller with a method inside, returning index.html.
I configured Zuul routing like this for UI (I'm using Eureka too):
zuul:
routes:
ui:
path: /ui/**
serviceId: myproject.service.ui
stripPrefix: false
sensitiveHeaders:
If I call http://localhost:8080/ui/ everything works fine and I see rendering of my index.html.
Is it possible to configure Spring Cloud in some way to make the following flow work: calling http://localhost:8080/ redirects us to controller of UI microservice, which returns index.html?
So the idea is to open UI from the root of my site.
Thanks in advance!

Finally, I've made my code work! Thanks to #pan for mentioning Zuul Routing on Root Path question and #RzvRazvan for revealing about how Zuul routing works.
I've just added controller to Zuul routed Gateway microservice with one endpoint to redirect from root http://localhost:8080/ to http://localhost:8080/ui/:
#Controller
public class GateController {
#GetMapping(value = "/")
public String redirect() {
return "forward:/ui/";
}
}
Zuul properties for redirecting from Gateway microservice on port 8080 as http://localhost:8080/ui/ to UI microservice, which implemented as a separate Spring Boot application on port 8090 as http://localhost:8090/ui/:
zuul:
routes:
ui:
path: /ui/**
serviceId: myproject.service.ui
stripPrefix: false
sensitiveHeaders:
UI microservice's properties:
server:
port: 8090
servlet:
contextPath: /ui
Eventually, this call http://localhost:8080/ redirects us to controller of UI microservice, which returns view index.html:
#Controller
public class UiController {
#GetMapping(value = "/")
public String index() {
return "index.html";
}
}
Actually, I had another problem with rendering static content in such architecture, but it was connected with configuration of my front-end, which I develop using Vue.js framework. I will describe it here in a few sentences, in case it might be helpful for someone.
I have the following folders structure of UI microservice:
myproject.service.ui
└───src/main/resources
└───public
|───static
| ├───css
| └───js
└───index.html
All content of public folder is generated by npm run build task from webpack and vue.js. First time, I called my http://localhost:8080/ I got 200 OK for index.html and 404 for all other static resources, because they was called like this:
http:\\localhost:8080\static\js\some.js
So it was configured wrong public path for static assets in webpack. I changed it in config\index.js:
module.exports = {
...
build: {
...
assetsPublicPath: '/ui/',
...
}
...
}
And static assets became to be called properly. e.g.:
http:\\localhost:8080\ui\static\js\some.js

If you would like to have on Zuul the UI(front-end) you can add the static content in resources/static folder(html, css and js files). On this way your proxy is able to render the index.html (of course you must have an index.html in static folder). O this way on http://localhost:8080 the proxy will render index.html; also you can have another paths but all these path are managed by index.html)
About routing, the Zuul only redirect the http request. http://localhost:8080/ui/. On 8080 is running the proxy (Zuul) BUT /ui is the context path of resource server. Se when you make a call on this path http://localhost:8080/ui/ the proxy will redirect to resource server and will actually make a request to http://localhost:8090/ui/
It is a difference between browser path and http request path. The browser path is managed by index.html and the http request is managed by Zuul. I don't know if I was explicit enough.
One more thing... You can have the same path (/ui) on http request and index.html and when your browser will access the http://localhost:8080/ui/ a .js file with http request method will make an http request to http://localhost:8080/ui/ and then will be redirected to http://localhost:8090/ui/ and the response from the resource server will be rendered on the page from http://localhost:8080/ui/.

Related

How to redirect to https with Spring cloud gateway & ribbon

I have 2 microservices working with https, I added spring cloud gateway api to centralize the routes but I faced a problem where it says: This combination of host and port requires TLS I'm pretty sure that's because of the routes configuration on my gateway, I dont have much experience on this side but if someone could help me.
this is my spring gateway routes configuration :
#Bean
public RouteLocator gatewayRouter(RouteLocatorBuilder builder){
return builder.routes()
.route(p -> p.path("/api/v1/**")
.uri("lb://statement"))
.route( p -> p.path("/api/v3/**")
.uri("lb://activiti-workflow"))
.build();
}
Please I just want to know if this configuration will redirects to https or not, because while sending http requests directly to the microservices it works but with gateway is doesn't.
If your backend services in eureka provide https, your can set route uri like this:
uri: lb:https://your-service-name
Or
.uri("lb:https://your-service-name")
It just like websocket configuration. The key class is org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter
More info see at: https://cloud.spring.io/spring-cloud-gateway/reference/html/#the-routetorequesturl-filter
If your backend services use insecure HTTPS cert, your may need config this:
spring:
cloud:
gateway:
httpclient:
ssl:
useInsecureTrustManager: true
See at: https://cloud.spring.io/spring-cloud-gateway/reference/html/#tls-and-ssl

Zuul Proxy does NOT work on Tomcat vai SpringBootServlet

I'm seeking for a help with an issue I'm facing with Zuul which is not working on Tomcat being packaged into WAR.
Standalone it works perfectly well, but when I change packaging to war and deploy to Tomcat - requests does not seem to reach Zuul.
I have extended SpringBootServletInitializer and overridden configure() method, but that does not help.
Note: please do NOT advise me to run SpringBoot standalone with embedded Tomcat - that does not work as I need to incorporate an API gateway into existing infrastructure set up. In other words I need to implement a gateway given a boundary condition - it has to be deployed on Tomcat application server.
#SpringBootApplication
#EnableZuulProxy
public class GatewayApplication extends SpringBootServletInitializer {
...
#override
protected StringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(GatewayApplication.class);
}
}
application.yml
zuul:
routes:
freebeer:
path: "/beer/**"
url: "https://freedom.com:443"
default:
path: "/**"
url: "http://landing.com/"
It works perfectly fine when I'm running standalone app with embedded Tomcat e.g.:
- request to http://localhost:8080/ is nicely redirected to http://landing.com/
- as well as ..:8080/beer is nicely redirected to freedom.com
But in case of WAR deployed to Tomcat - nothing works:
- request to http(s)://tomcat.intranet.com:12345 welcomes me with message that nothing is there and suggests to add web content
- request to http(s)://tomcat.intranet.com:12345/beer gives me 404 with message that origin server did not find a current representation for the target resource or that it's not willing to disclose that one exists
Looks like I'm missing something very obvious. But I've run out of patience to figure it out and calling for help :)
Resolved. Requests were simply sent to wrong context - to app server root instead of web app specific. I solved it by naming war as ROOT.war

Handling of requests locally by Zuul Gateway server

How do I make Spring Boot Zuul Proxy Server handle a specific request locally, instead of proxying it to some other Server?
Let's say I want to do a custom health check of Zuul Proxy Server itself through an API which should return a local response, instead of returning a proxied response from some other remote server.
What kind of route configuration is required to forward the request?
Following is what I figured out and it worked for me:
1) Create a local request handler:
Add a regular Controller/RestController with a RequestMapping in a file in Zuul proxy Server code
#RestController
public class LocalRequestHandler {
#GetMapping(path = "/status", produces = MediaType.TEXT_PLAIN_VALUE);
private static ResponseEntity<String> getServiceStatus() {
String status = "I am alive";
return ResponseEntity.ok().body(status);
}
}
2) Create a local forwarding route in the configuration file (application.properties or as the case may be) where other routes are defined. In my case, Spring Boot Zuul Proxy server is running on Jetty container with GatewaySvc as the application context.
zuul.routes.gatewaysvc.path=/GatewaySvc/status
zuul.routes.gatewaysvc.url=forward:/GatewaySvc/status
For a standalone Spring Boot, which I have not tested, you may have to remove the context path from the above configuration.
zuul.routes.gatewaysvc.path=/status
zuul.routes.gatewaysvc.url=forward:/status
Reference:
Strangulation Patterns and Local Forwards

Spring-Cloud Zuul breaks UTF-8 symbols in forwarded multipart request filename

this is first time for me on SO, so please be patient for my first question.
I think i have some kind of configuration problem, but after a day of experiments i'm stuck. Our application is based on Spring-Cloud [Brixton release]. We have configuration like this: Portal (web application serving angular-based web-ui), which has zuul proxy with single route configured to our gateway service, like so:
zuul:
ignoredServices: '*'
prefix: /api
routes:
api-proxy:
path: /**
serviceId: api-gateway
which has another Zuul configured and relays requests to inner bussiness logic services:
zuul:
ignoredServices: '*'
routes:
service1:
path: /service1/**
serviceId: service1
service2:
path: /service2/**
serviceId: service2
All this configuration is working with no problem.
The problem now that i am facing is with file upload multipart requests. To be more precise - those multipart requests, when file to be uploaded has non latin symbols (e.g. ąčęėįš) from UTF-8. When request reaches service which has to deal with #RequestPart MultipartFile file, then file.getOriginalFilename() returns questionmarks in the places of aforementioned symbols. Now, i have tried to directly upload such file to such controller, and filename comes without questionmarks, that is, not broken, which suggests, that some bad interpretation/parsing of multipart request occurs somewhere in Zuul filters, when proxy relays incomming request.
Maybe someone had similar experience with Zuul and can direct me some way to resolve this problem?
I just ran into the same issue myself, and created the following issue:
https://jira.spring.io/browse/SPR-15396
Hopefully this is getting configurable in Spring 4.3.8.
In the meantime, you have to create a bean of type FormBodyWrapperFilter (that overrides the one in ZuulConfiguration). In the constructor, you pass a copy of FormHttpMessageConverter, which extends from FormHttpMessageConverter, and you change the encoding used in FormHttpMessageConverter.MultipartHttpOutputMessage#getAsciiBytes(String) to UTF-8 (you might also want to delete any references to javax-mail, unless you have that on classpath). You need a pretty recent version of Spring Cloud Netflix to do this.
Example:
#Bean
FormBodyWrapperFilter formBodyWrapperFilter() {
return new FormBodyWrapperFilter(new MyFormHttpMessageConverter());
}
Then you create a copy of FormHttpMessageConverter, and change the following method:
private byte[] getAsciiBytes(String name) {
try {
// THIS IS THE ONLY MODIFICATION:
return name.getBytes("UTF-8");
} catch (UnsupportedEncodingException ex) {
// Should not happen - US-ASCII is always supported.
throw new IllegalStateException(ex);
}
}
Still having issues after modifying response even with newer versions
Using spring boot 2.3.8.RELEASE
Managed to fix it by forcing the following spring properties
server.servlet.encoding.force= true
server.servlet.encoding.charset= UTF-8

Spring Security Oauth2 SSO with Zuul Proxy

I'm modifying the oauth2-vanilla sample from Springs excellent security tutorials. The oauth2-vanilla combines the Zuul Proxy and the UI into a single application. I would like to seperate the Zuul Proxy and the UI. (The Zuul Proxy should act as an API gateway and as a reverse proxy for several UIs).
When accessing the UI via the zuul proxy, it should be able to do SSO based on Oauth2 between the UI and the resource backend.
The oauth2-vanilla looks like this
Where I want to move to something like this :
I've removed the UI part from the gateway, and added a zuul route for the ui
zuul:
routes:
resource:
url: http://localhost:9000
user:
url: http://localhost:9999/uaa/user
ui:
url: http://localhost:8080
I created a new UI webapp containing the UI (Angular stuff) with an #EnableOAuth2Sso annotation.
So I'm accessing the UI via http://localhost:8888 (through the zuul proxy).
After authenticating and doing through the UI flow, I can access the /user endpoint that returns me the user. (During debugging, I see that when I access the /user endpoint that I have an HTTP Session with an OAuth2Authentication.
When I access the /resource endpoint however, the HttpSessionSecurityContextRepository cannot find a session and is unable to build a context with the OAuth2Authentication.
I've created a git repository with the modified sample.
I'm guessing there is something wrong with the gateway configuration.
I've tried changing cookie paths, changing HttpSecurity rules in the proxy but I cannot get it to work.
What I don't understand is why the UI, when accessed through the proxy is able to resolve the /user endpoint fine (with an HTTP session and a OAuth2Authentication), but it is unable to access the /resource endpoint.
Also, as the UI is now running in the /ui context, it seems that I need to have the following code in the gateway for it to load up the angular css / js files.
.antMatchers("/ui/index.html", "/ui/home.html", "ui/css/**", "/ui/js/**").permitAll().anyRequest().authenticated();
It also doesn't seem right that I need to prefix it with the zuul ui route.
Any help would be appreciated.
I was never able to get the #EnableOauthSso to work. Instead, I annotated as an #EnableResourceServer and created a security config for Zuul.
#Configuration
#EnableResourceServer
public class JwtSecurityConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/**").permitAll()
.antMatchers("/**").hasAuthority("ROLE_API")
.and()
.csrf().disable();
}
}

Resources