Zuul Proxy does NOT work on Tomcat vai SpringBootServlet - spring-boot

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

Related

Spring boot, tomcat, rest api 404

I am using Kotlin + Gradle and trying to build a war file to deploy on Tomcat. My application is from the https://start.spring.io plus a simple controller and build the war file using ./gradlew bootWar
#SpringBootApplication
class ServletInitializer : SpringBootServletInitializer() {
override fun configure(application: SpringApplicationBuilder): SpringApplicationBuilder {
return application.sources(DemoApplication::class.java)
}
}
#RestController
class TomcatController {
#GetMapping("/hello")
fun sayHello(): Collection<String> {
return IntStream.range(0, 10)
.mapToObj { i: Int -> "Hello number $i" }
.collect(Collectors.toList())
}
}
when I try to access it I get
Type Status Report
Message The requested resource [/demo-0.0.1-SNAPSHOT/hello] is not available
Description The origin server did not find a current representation for the target resource or is not willing to disclose that one exists.
I am super stuck. What am I doing wrong? If I add a html file to the src/main/webapp/index.html it shows up for some reason only the rest api can't be reached.
Spring Boot applications come with a built in Servlet. You are probably already using this feature when launching the application inside your IDE.
This basically means that you can just run your .jar file on any web server and it will be ready to go without setting up an extra tomcat instance.
However, if you want to build a Spring Boot application as a war file and deploy it to an external tomcat, you need to follow some extra steps as explained in this article.
Assuming from what you posted so far: the path that is returned shows another route before your actual controller route "/demo-0.0.1-SNAPSHOT/hello" is this "/demo-0.0.1-SNAPSHOT" the path that your application runs on ? If not it should be included in your controller (assuming you havent set it elsewhere for e.g. in your application.properties).
for e.g. http://localhost:8080/ would be the basepath and either http://localhost:8080/demo-0.0.1-SNAPSHOT/hello or http://localhost:8080/hello would point to your controller. Also your startup logs (for Tomcat and Spring) might give away more about the issue.

How to serve single-page app in Spring Boot?

I'm trying to do something very simple in Spring Boot:
Serve my api calls from /api
Serve a single-page app located in src/main/resources/static
Shouldn't be that hard, but this question has been asked a dozen times in different ways, and there doesn't seem to be an answer. It's very easy to do in Dropwizard, or when you wire up Jersey and Jetty together directly.
The best answer so far is here:
#Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/{spring:\\w+}")
.setViewName("forward:/");
registry.addViewController("/**/{spring:\\w+}")
.setViewName("forward:/");
registry.addViewController("/{spring:\\w+}/**{spring:?!(\\.js|\\.css)$}")
.setViewName("forward:/");
}
}
The problem with this is that calls to /api/bad_missing_path get routed to the SPA, and not to an error message that says this is a bad api call. The other problem with it is that I just don't understand it. Yet another problem is it explicitly mentions .js and .css file types, and I'm going to have many more types than that. I want everything that starts with /api to be treated as an api call, and everything that doesn't start with /api to get passed through to the /static directory.
I have also tried to mount the DefaultServlet on "/*" but it didn't catch anything, either using the default Tomcat server or when I switched to Jetty.
How do I get this to work?

Accessing tomcat management page from Spring tool set 4

I have developed a Camel Rout using Spring. I used the STS4 IDE to develop the same.
When I started the application using Run As-> Spring Boot App, the application starts and also I can see from the logs that the route is started.
My route is a basic app, the exposes a rest endpoint and logs a Hello World
#Override
public void configure() throws Exception {
restConfiguration()
.enableCORS(true)
.apiContextPath("/api-doc")
.apiProperty("api.title", "Test REST API")
.apiProperty("api.version", "v1")
.apiContextRouteId("doc-api")
.component("servlet")
.bindingMode(RestBindingMode.json);
rest("/api/")
.id("api-route")
.consumes("application/json")
.get("/test")
.to("direct:log");
from("direct:log")
.id("log")
.log(LoggingLevel.INFO,"Test successful");
}
What I am expecting is that if I do localhost:8080/api/test, i will see some logs "Test Susccessful" in the Tomcat logs. I am using tomcat 9, Instead what I get WhiteLable error. I thought there is an issue with my code so I tried localhost:8080 and i was expecting the Tomcat Management server to open. Even that is not working.
I am not starting Tomcat separately. What I am doing is Run As-> Spring Boot App and I guess it is calling the embedded tomcat.
Credit for this answer goes to #Bedla. I had to add camel in the URL path http://localhost:8080/camel/api/test

Spring Cloud: default redirecting from Gateway to UI

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/.

Requested resource is not available in tomcat 7

I have created an web application based on spring mvc After I deployed it, in Tomcat manager the application is shown and it has been deployed successfully. But when I am accessing the web application it is giving me error saying requested resource is not available.
In log files there are no errors so far. Please help.
Regards,
Shruti
As you are using Spring MVC,
You should have SpringController in your project.
So in your each controller -
for each method there should be
a #RequestMapping(value = "/login", method = RequestMethod.GET) portion.
So your application url should be something like -
<<web server address>>/<your deployed war file name>/<The Request mapping url>
i.e.
something like -
http://localhost:8080/samplewebproject/login
which will give you the requested resource.

Resources