I have a simple Spring MVC Java Application structure:
Spring Version 5.2.3
I am using JSPs as views. (Only have 2 at this point - so super simple).
index.jsp and index2.jsp
On index.jsp I am doing some authentication.
On index2.jsp - this is the view after user has been authenticated.
So index.jsp is rendering fine when I hit the URL in the browser. I do some stuff and then I have a JQuery post call that calls up the Controller and passes it a few things.
Here's the AJAX POST call -
function validateLoginServerSide(eventObj) {
var data = JSON.stringify({
"UIDSignature": eventObj.UIDSignature,
"firstName": eventObj.profile.firstName
});
$.ajax({
url: 'cdc/validate',
headers: {
'Content-Type': 'application/json'
},
method: 'POST',
dataType: 'text',
data: data,
success: function(data){
console.log('succes: ' + data);
},
error: function(jqXHR, status, error) {
console.log('error: ' + error);
}
});
}
Here's the Controller -
#RequestMapping(value = "/validate", method=RequestMethod.POST,
consumes = {MediaType.APPLICATION_JSON_VALUE })
public String validateAuthentication(
#RequestBody CompanyBO signature, ModelMap model) {
model.addAttribute("firstName", signature.getFirstName());
return "index2"; // return internal application page
}
index2 as previously mentioned is a JSP and is located in the following directory in my project:
src/main/webapp
Here's what I don't understand - notice in my post callback in the success function - I print out data.
Well, in the console of my browser I see the contents of my JSP (index2.jsp) perfectly formatted html and even that one binding that resolved to the firstName that I passed into that method, but the browser window itself is still on the original view, index.jsp - so the new jsp is not rendered to the browser window - but it is FOUND, binding resolved, and as you will see below in the logs FORWARDED.
I did some research and I noticed some posts saying that one needs to include this in their POM:
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>...</version>
</dependency>
The version is dependent on the version of Tomcat that you are running (so the blogs have stated) --- and the reason for this is because Spring MVC doesn't know how to render JSPs without help. Made sense to me so I tried it - but this didn't work. Still same result.
And finally just to prove I'm not crazy - here's some DEBUG statements from Tomcat (as promised):
22:56:00.676 [http-apr-8080-exec-6] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Read "application/json" to [CompanyBO(UIDSignature=1234567, firstName=Alex)]
22:56:00.702 [http-apr-8080-exec-6] DEBUG org.springframework.web.servlet.view.InternalResourceView - View name 'index2', model {org.springframework.validation.BindingResult.companyBO=org.springframework.validation.BeanPropertyBindingResult: 0 errors, firstName=Alex}
22:56:00.702 [http-apr-8080-exec-6] DEBUG org.springframework.web.servlet.view.InternalResourceView - Forwarding to [/index2.jsp]
22:56:00.946 [http-apr-8080-exec-6] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK
22:56:06.014 [http-apr-8080-exec-8] DEBUG org.springframework.web.servlet.DispatcherServlet - GET "/company/resources/javascript/lib/bootstrap.bundle.js.map", parameters={}
22:56:06.072 [http-apr-8080-exec-8] DEBUG org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapped to ResourceHttpRequestHandler ["/resources/"]
22:56:06.082 [http-apr-8080-exec-9] DEBUG org.springframework.web.servlet.DispatcherServlet - GET "/company/resources/css/lib/bootstrap.min.css.map", parameters={}
22:56:06.084 [http-apr-8080-exec-9] DEBUG org.springframework.web.servlet.handler.SimpleUrlHandlerMapping - Mapped to ResourceHttpRequestHandler ["/resources/"]
22:56:06.186 [http-apr-8080-exec-8] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK
22:56:06.202 [http-apr-8080-exec-9] DEBUG org.springframework.web.servlet.DispatcherServlet - Completed 200 OK
Million dollar question: How is it that the view is found, returned but not rendered?
Related
I have two applications
a. monolith (developed with java servlet)
b. Spring boot microservice (in development)
I am trying to develop spring cloud api gateway which will sit infront of this two apps and will serve the traffic based on what request it receives. Mostly both apps support POST method and routing in api gateway works fine for b.spring boot microservice but when same request and url I tried on monolith its been observed that spring cloud api gateway sending GET request (which is not allowed ) and getting failed with 404 error. Is there any way to identify what exact request api gateway tried ? OR does api gateway try first GET and then POST ?
I am able to confirm that I am receiving GET request on the POST request that I tried on api gateway by checking the access logs
0:0:0:0:0:0:0:1 - - [14/Jul/2022:12:34:31 -0700] "**GET** /myservice/revers HTTP/1.1" 404 1685 "PostmanRuntime/7.29.0" "0/455"
logs from api gateway after enabling the TRACE
2022-07-15 01:04:30.426 INFO 16016 --- [ctor-http-nio-3] c.t.tes.gwapi.config.LoggingFilter : Incoming request http://localhost:8080/servlet ,is routed uri:http://10.2.1.55:3068/myservice/revers with id: my-route-id
2022-07-15 01:04:31.665 DEBUG 16016 --- [ctor-http-nio-3] r.netty.http.client.HttpClientConnect : [d95e4f2a-1, L:/10.01.57.01:59773 - R:/10.2.1.55:3068] Handler is being applied: {uri=http://10.2.1.55:3068/myservice/revers , method=POST}
2022-07-15 01:04:31.974 DEBUG 16016 --- [ctor-http-nio-3] r.n.http.client.HttpClientOperations : [d95e4f2a-1, L:/10.01.57.01:59773 - R:/10.2.1.55:3068] Received response (auto-read:false) : [Date=Thu, 14 Jul 2022 19:34:31 GMT, Server=Apache, Last-Modified=Wed, 06 Jul 2022 09:15:29 GMT, Accept-Ranges=bytes, Content-Type=text/html, content-length=1685]
2022-07-15 01:04:31.983 DEBUG 16016 --- [ctor-http-nio-3] r.n.http.client.HttpClientOperations : [d95e4f2a-1, L:/10.01.57.01:59773 - R:/10.2.1.55:3068] Received last HTTP packet
2022-07-15 01:04:31.987 INFO 16016 --- [ctor-http-nio-3] c.t.t.gwapi.config.SpringCloudConfig : Response body <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
sample html
Here is sample api config
#Bean
public RouteLocator myRouteSavingRequestBody(RouteLocatorBuilder builder) {
return builder.routes()
.route("my-route-id",
p -> p
.path("/servlet/**") //your own path filter
.filters(f -> f
.modifyResponseBody(String.class, String.class,
(webExchange, originalBody) -> {
if (originalBody != null) {
//log.info("Response body {}", originalBody);
return Mono.just(originalBody);
} else {
return Mono.empty();
}
})
.modifyRequestBody(String.class, String.class,
(webExchange, originalBody) -> {
if (originalBody != null) {
// log.info("Request body {}", originalBody);
return Mono.just(originalBody);
} else {
return Mono.empty();
}
})
.setPath("/myservice/revers")
)
.uri("http://10.2.1.55:3068")
)
.build();
}
im trying to to read a value from Google-Cloud storage from my Spring application. I use the Spring Cloud GCP extension to work with Google Cloud Storage.
My Pom.xml for the gcp dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gcp-starter-storage</artifactId>
<version>1.1.2.RELEASE</version>
</dependency>
When i try to read a file from my rest-endpoint i get the exception(at the end of my answer) that somehow that my token could not be refreshed ? Where i can set my clientId or is there something else going on ? I used the code from the sample application which is provided by pivotal and google.
#RestController
public class GCloudStorageController {
#Value("gs://test_files_test/test.txt")
private Resource gcsFile;
#RequestMapping(value = "/cloud", method = RequestMethod.GET)
public String readGcsFile() throws IOException {
return StreamUtils.copyToString(
this.gcsFile.getInputStream(),
Charset.defaultCharset()) + "\n";
}
#RequestMapping(value = "/cloud", method = RequestMethod.POST)
String writeGcs(#RequestBody String data) throws IOException {
try (OutputStream os = ((WritableResource) this.gcsFile).getOutputStream()) {
os.write(data.getBytes());
}
return "file was updated\n";
}
}
2019-08-20 20:27:02.555 DEBUG 12348 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Failed to complete request: com.google.cloud.storage.StorageException: 400 Bad Request
{
"error": "invalid_grant",
"error_description": "Bad Request"
}
2019-08-20 20:27:02.556 DEBUG 12348 --- [nio-8080-exec-1] o.s.s.w.header.writers.HstsHeaderWriter : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher#24f1dc0f
2019-08-20 20:27:02.557 DEBUG 12348 --- [nio-8080-exec-1] w.c.HttpSessionSecurityContextRepository : SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
2019-08-20 20:27:02.557 DEBUG 12348 --- [nio-8080-exec-1] s.s.w.c.SecurityContextPersistenceFilter : SecurityContextHolder now cleared, as request processing completed
2019-08-20 20:27:02.563 ERROR 12348 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is com.google.cloud.storage.StorageException: 400 Bad Request
{
"error": "invalid_grant",
"error_description": "Bad Request"
}] with root cause
com.google.api.client.http.HttpResponseException: 400 Bad Request
{
"error": "invalid_grant",
"error_description": "Bad Request"
}
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1094) ~[google-http-client-1.30.1.jar:na]
at com.google.auth.oauth2.UserCredentials.refreshAccessToken(UserCredentials.java:193) ~[google-auth-library-oauth2-http-0.16.1.jar:na]
at com.google.auth.oauth2.OAuth2Credentials.refresh(OAuth2Credentials.java:165) ~[google-auth-library-oauth2-http-0.16.1.jar:na]
at com.google.auth.oauth2.OAuth2Credentials.getRequestMetadata(OAuth2Credentials.java:151) ~[google-auth-library-oauth2-http-0.16.1.jar:na]
at com.google.auth.http.HttpCredentialsAdapter.initialize(HttpCredentialsAdapter.java:96) ~[google-auth-library-oauth2-http-0.16.1.jar:na]
at com.google.cloud.http.HttpTransportOptions$1.initialize(HttpTransportOptions.java:159) ~[google-cloud-core-http-1.79.0.jar:1.79.0]
at com.google.cloud.http.CensusHttpModule$CensusHttpRequestInitializer.initialize(CensusHttpModule.java:109) ~[google-cloud-core-http-1.79.0.jar:1.79.0]
at com.google.api.client.http.HttpRequestFactory.buildRequest(HttpRequestFactory.java:88) ~[google-http-client-1.30.1.jar:na]
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.buildHttpRequest(AbstractGoogleClientRequest.java:430) ~[google-api-client-1.30.1.jar:1.30.1]
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:549) ~[google-api-client-1.30.1.jar:1.30.1]
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:482) ~[google-api-client-1.30.1.jar:1.30.1]
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:599) ~[google-api-client-1.30.1.jar:1.30.1]
at com.google.cloud.storage.spi.v1.HttpStorageRpc.get(HttpStorageRpc.java:433) ~[google-cloud-storage-1.79.0.jar:1.79.0]
at com.google.cloud.storage.StorageImpl$5.call(StorageImpl.java:240) ~[google-cloud-storage-1.79.0.jar:1.79.0]
at com.google.cloud.storage.StorageImpl$5.call(StorageImpl.java:237) ~[google-cloud-storage-1.79.0.jar:1.79.0]
at com.google.api.gax.retrying.DirectRetryingExecutor.submit(DirectRetryingExecutor.java:105) ~[gax-1.46.1.jar:1.46.1]
at com.google.cloud.RetryHelper.run(RetryHelper.java:76) ~[google-cloud-core-1.79.0.jar:1.79.0]
at com.google.cloud.RetryHelper.runWithRetries(RetryHelper.java:50) ~[google-cloud-core-1.79.0.jar:1.79.0]
at com.google.cloud.storage.StorageImpl.get(StorageImpl.java:236) ~[google-cloud-storage-1.79.0.jar:1.79.0]
at com.google.cloud.storage.StorageImpl.get(StorageImpl.java:254) ~[google-cloud-storage-1.79.0.jar:1.79.0]
at org.springframework.cloud.gcp.storage.GoogleStorageResource.getBlob(GoogleStorageResource.java:165) ~[spring-cloud-gcp-storage-1.1.2.RELEASE.jar:1.1.2.RELEASE]
at
Thank you Joe. The resource to implement 'Spring Cloud GCP Core' was never mentioned in the tutorials or i overlooked it.
Somehow another account was connected in my Google Cloud SDK on my console. So i used
gcloud auth application-default login
and logged in the right account. Now it works. Thank you.
This looks like an issue regarding authentication. Did you follow the generic 'Spring Cloud GCP Core' [1] configuration?
Check your application.properties [2] (or other configuration) and make sure it contains at least the following properties:
spring.cloud.gcp.datastore.project-id=XXX
spring.cloud.gcp.datastore.credentials.location=YYY
or choose an other method shown in [1].
[1] https://cloud.spring.io/spring-cloud-static/spring-cloud-gcp/1.1.2.RELEASE/single/spring-cloud-gcp.html#spring-cloud-gcp-core
[2] https://github.com/spring-cloud/spring-cloud-gcp/blob/master/spring-cloud-gcp-samples/spring-cloud-gcp-data-datastore-sample/src/main/resources/application.properties
I am having a issue related to authentication where I am getting logged out of my app when trying to GET from an endpoint that was created from a POST (HTTTP STATUS 201) I see the following errors. The backend is seeing the user as anonymousUser while I am logged in but works fine for another endpoint in the same file :
2018-10-22 11:33:35.251 DEBUG 2124 --- [ XNIO-8 task-23]
c.c.link.aop.logging.LoggingAspect : Enter:
org.springframework.boot.actuate.audit.AuditEventRepository.add() with
argument[s] = [AuditEvent [timestamp=Mon Oct 22 11:33:35 PDT 2018,
principal=anonymousUser, type=AUTHORIZATION_FAILURE,
data={details=org.springframework.security.web.authentication.WebAuthenticationDetails#fffed504:
RemoteIpAddress: 127.0.0.1; SessionId:
_5aP-S8x27gGSIjtbkR6EwrWOD9Yybnd-4M3z0ol, type=org.springframework.security.access.AccessDeniedException,
message=Access is denied}]] 2018-10-22 11:33:35.258 DEBUG 2124 --- [
XNIO-8 task-23] c.c.link.aop.logging.LoggingAspect : Exit:
org.springframework.boot.actuate.audit.AuditEventRepository.add() with
result = null 2018-10-22 11:33:35.343 WARN 2124 --- [ XNIO-8 task-23]
o.z.p.spring.web.advice.AdviceTrait : Unauthorized: Full
authentication is required to access this resource
The same resource (DeliveryResource.java) has an endpoint that works fine
the only difference between both end points is one is /getList (this one is working fine) VS. /getPackingListReport/{number} (this one fails authentication).
The API definitions are shown below:
#GetMapping("/getPackingListReport/{number}")
#Secured(AuthoritiesConstants.USER)
#Timed
public ArrayList<WebOrder> getPackingListReportFromDB(#PathVariable("number") long packingListNbr)
vs.
#GetMapping("/getList")
#Secured(AuthoritiesConstants.USER)
#Timed
public WebOrder getList(#RequestParam(value = "custid") long custid,#RequestParam(value = "pId") long pId) {
I found the problem.
I was using the following for the "/getList" mapping:
// call dao to insert to DB the list and then call the stored proc
URI location = ServletUriComponentsBuilder.fromCurrentContextPath().path("/api/rest/getPackingListReport/{packingListNumber}").buildAndExpand(packingListNumber).toUri();
return ResponseEntity.created(location).build();
to return a created resource URI (HTTP STATUS 201) after a POST. That path contained the incorrect URI starting with , "http://localhost" when jHipster is currently default set to only handle and look for "/api" or in my case i added "/rest/api/*" on the Angular5 side.
I fixed the issue by filtering out any characters before "/api/" after receiving the URL.
I'm building spring mvc application with spring security.
This is my url :
http://localhost:8080/inbalUI/login
And I'm getting to my controller :
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginPage() {
if (isCurrentAuthenticationAnonymous()) {
return "login";
} else {
return "login";
// return "redirect:/list";
}
}
This is the log :
20:02:10.823 [http-nio-8080-exec-10] DEBUG org.springframework.web.servlet.view.JstlView - Forwarding to resource [/WEB-INF/views/login.jsp] in InternalResourceView 'login'
20:02:10.825 [http-nio-8080-exec-10] DEBUG org.springframework.security.web.context.HttpSessionSecurityContextRepository - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
20:02:10.825 [http-nio-8080-exec-10] DEBUG org.springframework.web.servlet.DispatcherServlet - Successfully completed request
20:02:10.825 [http-nio-8080-exec-10] DEBUG org.springframework.security.web.access.ExceptionTranslationFilter - Chain processed normally
20:02:10.825 [http-nio-8080-exec-10] DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
This is the login.jsp deploying path on tomcat :
C:\me\apache\apache-tomcat-8.0.36\webapps\inbalUI\WEB-INF\classes\WEB-INF\views
But I'm getting HTTP Status 404:
HTTP Status 404 - /inbalUI/WEB-INF/views/login.jsp
type Status report
message /inbalUI/WEB-INF/views/login.jsp
description The requested resource is not available.
Apache Tomcat/8.0.36
Any idea why ?
It seems to me that you use the wrong folder for views.
According to this article https://vitalflux.com/web-application-folder-structure-spring-mvc-web-projects/ this folder should be at:
src/WEB-INF/views/login.jsp
and you probably put it under
src/resources/WEB-INF/views/login.jsp
Which results in WEB-INF/views/login.jsp being put into the classpath (classes/WEB-INF/views/login.jsp)
I want to better understand how Tomcat handles requests and why my specific issue may be happening.
I am trying to enhance my existing Spring MVC web application with the Netflix Hystrix framework. This involves adding a hystrix-specific servlet to handle requests ending with /hystrix.stream.
Based on the logs (below), this mapping works and the request is being forwarded to the correct servlet. However, the exception that is thrown does not occure in the servlet. I have also tried extending the servlet to add additional logging - but it appears that no methods in the servlet are called. The exception seems to be happening because of some inner working on Tomcat that I am not aware of.
Here is a snippet from my web.xml (note that the rest of my application works fine - this is just concerning requests for /hystrix.stream):
<servlet>
<display-name>HystrixMetricsStreamServlet</display-name>
<servlet-name>HystrixMetricsStreamServlet</servlet-name>
<servlet-class>com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HystrixMetricsStreamServlet</servlet-name>
<url-pattern>/hystrix.stream</url-pattern>
</servlet-mapping>
When I navigate to loalhost:8080/web-app/hystrix.stream I am forwarded to the Tomcat 404 Error. The following exception appears in tomcat's log file:
2014-04-16 15:53:22 DEBUG AuthenticatorBase:419 - Security checking request GET /web-app/hystrix.stream
2014-04-16 15:53:22 DEBUG WebappClassLoader:1582 - loadClass(com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet, false)
2014-04-16 15:53:22 DEBUG WebappClassLoader:1598 - Returning class from cache
2014-04-16 15:53:22 DEBUG RealmBase:617 - No applicable constraints defined
2014-04-16 15:53:22 DEBUG AuthenticatorBase:501 - Not subject to any constraint
2014-04-16 15:53:22 DEBUG [localhost]:449 - Processing ErrorPage[errorCode=404, location=/404.htm]
2014-04-16 15:53:22 DEBUG Http11Processor:986 - Error parsing HTTP request header
java.io.EOFException: Unexpected EOF read on the socket
at org.apache.coyote.http11.InternalInputBuffer.parseRequestLine(InternalInputBuffer.java:99)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:952)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:313)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
2014-04-16 15:53:22 DEBUG Http11Protocol:645 - Socket: [org.apache.tomcat.util.net.SocketWrapper#56a7cbf2:129bf96a[TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: Socket[addr=/0:0:0:0:0:0:0:1,port=53783,localport=8443]]], Status in: [OPEN_READ], State out: [CLOSED]
2014-04-16 15:53:22 DEBUG LimitLatch:126 - Counting down[http-bio-8443-exec-1] latch=4
2014-04-16 15:53:22 DEBUG Http11Processor:986 - Error parsing HTTP request header
java.io.EOFException: Unexpected EOF read on the socket
at org.apache.coyote.http11.InternalInputBuffer.parseRequestLine(InternalInputBuffer.java:99)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:952)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:313)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Has anyone encountered something like this before? As I mentioned, my application works fine - this only occures for /hystrix.stream. I've used the Chrome Postman plugin to add the Accept and Content-Type = application/json headers to the request - both without success. As far as I know, requests to this servlet do not have any header requirements
Thanks for the help.
issue message is very clear, your request head is not corrent.
byte chr = 0;
do {
// Read new bytes if needed
if (pos >= lastValid) {
if (!fill())//read request content
throw new EOFException(sm.getString("iib.eof.error"));
}
// Set the start time once we start reading data (even if it is
// just skipping blank lines)
if (request.getStartTime() < 0) {
request.setStartTime(System.currentTimeMillis());
}
chr = buf[pos++];
} while ((chr == Constants.CR) || (chr == Constants.LF));
above is the source code of tomcat in InternalInputBuffer.parseRequestLine
- *. first time in the while function will be read content (8*1024).
[usually your header won't be so long]
*. after you read request content, the code will be check the first charactor of '\r\n'
*. so if your request content won't be contains this charactors, will be throw EOF exception
*. then the header paser is faill, so the web container don't know the Servlet method, so your servlet won't be called.
i think the server is ok, the problem is appeared in Chrome Postman plugin, please check the header