POST with retrofit 2.0 - java

I'm using retrofit to communicate with my restful web service. The GET requests are working okay, the problem is when I try to make a POST request.
In my web service I have this method:
#POST
#Path("/byPeriodo")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public List<ItemProdutividade> getProdutividadeByPeriodo(#FormParam("dataInicial")
Date dataInicial, #FormParam("dataFinal") Date dataFinal,
#FormParam("cpf") long cpf){
return service.getProdutividadeByPeriodo(DateUtils.toLocalDate(dataInicial),
DateUtils.toLocalDate(dataFinal), cpf);
}
And in Android side I have this:
#FormUrlEncoded
#POST("produtividade/byPeriodo/")
Call<List<ItemProdutividade>> getProdutividadeByPeriodo(#Field("dataInicial") Date dataInicial,
#Field("dataFinal") Date dataFinal,
#Field("cpf") long cpf);
When I execute I get the following error:
HTTP STATUS 400 - BAD REQUEST -The request sent by the client was
syntactically incorrect.
Someone knows what I have to do?
EDIT:
Using the retrofit log, this is the output:
12-16 20:06:33.521 7333-8993/br.com.empresa.oprojeto D/OkHttp: --> POST /oprojeto.webservice/rest/produtividade/byPeriodo/ HTTP/1.1
12-16 20:06:33.521 7333-8993/br.com.empresa.oprojeto D/OkHttp: dataInicial=Tue%20Dec%2016%2020%3A06%3A33%20BRST%202014&dataFinal=Wed%20Dec%2016%2020%3A06%3A33%20BRST%202015&cpf=12345678987
12-16 20:06:33.521 7333-8993/br.com.empresa.oprojeto D/OkHttp: --> END POST (125-byte body)
12-16 20:06:33.581 7333-8993/br.com.empresa.oprojeto D/OkHttp: <-- HTTP/1.1 400 Bad Request (64ms)
12-16 20:06:33.581 7333-8993/br.com.empresa.oprojeto D/OkHttp: Server: Apache-Coyote/1.1
12-16 20:06:33.581 7333-8993/br.com.empresa.oprojeto D/OkHttp: Content-Type: text/html;charset=utf-8
12-16 20:06:33.581 7333-8993/br.com.empresa.oprojeto D/OkHttp: Content-Language: en
12-16 20:06:33.581 7333-8993/br.com.empresa.oprojeto D/OkHttp: Content-Length: 1033
12-16 20:06:33.581 7333-8993/br.com.empresa.oprojeto D/OkHttp: Date: Wed, 16 Dec 2015 22:06:31 GMT
12-16 20:06:33.581 7333-8993/br.com.empresa.oprojeto D/OkHttp: Connection: close
12-16 20:06:33.581 7333-8993/br.com.empresa.oprojeto D/OkHttp: OkHttp-Selected-Protocol: http/1.1
12-16 20:06:33.581 7333-8993/br.com.empresa.oprojeto D/OkHttp: OkHttp-Sent-Millis: 1450303593575
12-16 20:06:33.581 7333-8993/br.com.empresa.oprojeto D/OkHttp: OkHttp-Received-Millis: 1450303593591
12-16 20:06:33.581 7333-8993/br.com.empresa.oprojeto D/OkHttp: <!DOCTYPE html><html><head><title>Apache Tomcat/8.0.29 - Error report</title><style type="text/css">H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}.line {height: 1px; background-color: #525D76; border: none;}</style> </head><body><h1>HTTP Status 400 - Bad Request</h1><div class="line"></div><p><b>type</b> Status report</p><p><b>message</b> <u>Bad Request</u></p><p><b>description</b> <u>The request sent by the client was syntactically incorrect.</u></p><hr class="line"><h3>Apache Tomcat/8.0.29</h3></body></html>
12-16 20:06:33.581 7333-8993/br.com.empresa.oprojeto D/OkHttp: <-- END HTTP (1033-byte body)

I finally solved the problem. I was sending type java.util.Date as a parameter and I decided to change to type Long (or long). So, my web service method is now:
#POST
#Path("/byPeriodo")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public List<ItemProdutividade> getProdutividadeByPeriodo(#FormParam("dataInicial")
long dataInicial, #FormParam("dataFinal") long dataFinal,
#FormParam("cpf") long cpf){
return service.getProdutividadeByPeriodo(DateUtils.toLocalDate(new Date(dataInicial)),
DateUtils.toLocalDate(new Date(dataFinal)), cpf);
}
The secret was to change type Date to long and do that: new Date(long).

Related

Spring Actuator /info returns an empty body

How to add custom metrics to /info endpoint in Spring Actuator 2.7.0?
Currently have the following related to actuator.
I have verified that info.app.version can retrieve the proper value from pom.xml using #Value.
pom.xml
<version>0.0.1-SNAPSHOT</version>
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
<version>2.7.0</version>
</dependency>
application.properties
info.app.version=#project.version#
management.endpoint.info.enabled=true
management.endpoints.web.exposure.include=info,health
But despite this I am only getting an empty response on /info.
Response header:
< HTTP/1.1 200
< 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
< Content-Type: application/vnd.spring-boot.actuator.v3+json
< Transfer-Encoding: chunked
< Date: Wed, 15 Jun 2022 04:12:47 GMT
* Received 7 B chunk
* Received 5 B chunk
* Connection #26 to host localhost left intact
Response body :
{}
My understanding is any property under info is included in /info endpoint. Or does this not work on actuator v2+ ?
Source
From the Spring-Boot 2.6 release notes https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.6-Release-Notes#actuator-env-infocontributor-disabled-by-default
You need to enable the info env property:
management.info.env.enabled=true
Latest spring boot requires two things to be set up:
1- exposing the endpoint in application.properties file:
management.endpoints.web.exposure.include=info, health
You can use a wildcard and expose all endpoints if you want
management.endpoints.web.exposure.include=*
2- enabling info.env in application.properties:
management.info.env.enabled=true

Missing set-cookie header on POST method

When i perform a request using HTTP POST method from Angular, response comes without set-cookie header, contrary when I perform a request using HTTP GET method response comes with set-cookie Header.
I know that when POST method is used a preflight OPTIONS request is automatically issued by a browser. I am looking for advice what can i make so after POST method request client get set-cookie header as it already works with GET method?
My Angular request:
this.http.post<UserDto>("//localhost:8080/users", this.user, {withCredentials: true}).subscribe( user => {
alert("User created successfully.");
});;
Those are response headers i get:
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Methods: POST,PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: http://localhost:4200
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 0
Date: Sun, 05 May 2019 09:22:55 GMT
Expires: 0
Pragma: no-cache
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
And my request headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: pl-PL,pl;q=0.9,en-US;q=0.8,en;q=0.7
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Connection: keep-alive
Host: localhost:8080
Origin: http://localhost:4200
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
My Spring Security configuration:
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
cors().and().
csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and().addFilterBefore(
new StatelessCSRFFilter(), CsrfFilter.class);
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(ImmutableList.of("http://localhost:4200"));
configuration.setAllowedMethods(Arrays.asList("POST","PUT","DELETE","GET","OPTIONS"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
I have found such an advice:
" I got it to work by adding a response filter for the pre-flight OPTIONS request that works without credentials.
<security-constraint>
<display-name>No check for options</display-name>
<web-resource-collection>
<web-resource-name>All Access</web-resource-name>
<url-pattern>/*</url-pattern>
<http-method>OPTIONS</http-method>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
I am not sure how to implement that solution is spring.
The CORS configuration has been set up correctly on the SpringFramework backend, as the methods succeed as expected, and Angular does set the cookies for GET requests. It is only POST operations that do not succeed if not preceded by HTTP.GET request.

Change Spring WS Fault status code from 500 to 400

I have built Spring WS application (based on Spring WS 2.2.3) that exposes a small web service with couple of Operations. Each Operation receives input parameters to search a backend database and return response. Some of the parameters are mandatory (e.g. Street Name) and the Client have requested that if a request to the service is missing some of these mandatory parameters (e.g. empty Street Name) then my service should return proper SOAP Fault with HTTP status of 400.
My exception handling is working fine and I am able to return the correct SOAP Fault to the client if some a required parameter was missing form the request message and Spring WS takes care of the rest by wrapping a SOAP Fault and sends it back to the client with status code of 500 like the following:
HTTP/1.1 500 Internal Server Error
Server: Apache-Coyote/1.1
Accept: text/xml, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
SOAPAction: ""
Content-Type: text/xml;charset=utf-8
Content-Length: 503
Date: Thu, 10 Dec 2015 22:28:02 GMT
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring xml:lang="en">Street Name is required</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Which is good except that I really want the HTTP status code to be '400 Bad Request' instead of the '500 Internal Server Error' I can't figure out how to change the status code from 500 to 400 and get similar response like the following:
HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Accept: text/xml, text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
SOAPAction: ""
Content-Type: text/xml;charset=utf-8
Content-Length: 503
Date: Thu, 10 Dec 2015 22:28:02 GMT
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<SOAP-ENV:Fault>
<faultcode>SOAP-ENV:Client</faultcode>
<faultstring xml:lang="en">Street Name is required</faultstring>
</SOAP-ENV:Fault>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Any ideas?

How can I get a webapp to exit gracefully if I delete it's deployment while it has a thread running?

I have a Spring MVC webapp, that as part of its operation runs off and performances several SQL queries, that can take up to 15 minutes to run.
If you delete the deployment while a query is running, the weblogic log will print the following stacktrace:
POST /MyWebapp/submitQuery HTTP/1.1
x-requested-with: XMLHttpRequest
Accept-Language: en-nz
Referer: http://server:1111/mywebapp/
Accept: */*
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET4.0C; .NET4.0E)
Content-Length: 268
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=KgJ5VnFLpWTp1ZNjwt3p1D4FHxmSQnPpTTwX18TDyMxnpgGBXWTD!1657710130; ADMINCONSOLESESSION=tSWjVnXJb6MPn0Bj9h4FPWvyzHC5pbCf2H20ZgfGHLTKpykMN82m!802748838
]] Root cause of ServletException.
java.lang.NoClassDefFoundError: org/apache/log4j/DefaultThrowableRenderer
at org.apache.log4j.spi.ThrowableInformation.getThrowableStrRep(ThrowableInformation.java:87)
at org.apache.log4j.spi.LoggingEvent.getThrowableStrRep(LoggingEvent.java:413)
at org.apache.log4j.WriterAppender.subAppend(WriterAppender.java:313)
at org.apache.log4j.WriterAppender.append(WriterAppender.java:162)
at org.apache.log4j.AppenderSkeleton.doAppend(AppenderSkeleton.java:251)
at org.apache.log4j.helpers.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:66)
at org.apache.log4j.Category.callAppenders(Category.java:206)
at org.apache.log4j.Category.forcedLog(Category.java:391)
at org.apache.log4j.Category.log(Category.java:856)
at org.apache.commons.logging.impl.Log4JLogger.debug(Log4JLogger.java:166)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:989)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:300)
at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:183)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3717)
at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3681)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2277)
at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2183)
at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1454)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:207)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:176)
If you wait for queries to finish before deleting the deployment, then the errors will not be posted.
I've been told that it's not acceptable for this stacktrace to be thrown.
Two questions:
What actually happens if you delete a deployment while a thread is running?
How can I get Weblogic to handle it gracefully?

tomcat not sending the requested http-header

I have got a servlet deployed under tomcat/webapps directory and I try to send a curl request to it:
$~ curl -v http://localhost:8080/
* About to connect() to localhost port 8080 (#0)
* Trying 127.0.0.1...
* Adding handle: conn: 0x33e0ee0
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x33e0ee0) send_pipe: 1, recv_pipe: 0
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.30.0
> Host: localhost:8080
> Accept: */*
>
< HTTP/1.1 302 Found
* Server Apache-Coyote/1.1 is not blacklisted
< Server: Apache-Coyote/1.1
< Set-Cookie: JSESSIONID=<ID>; Path=/; HttpOnly
< Location: http://localhost:8080/
< Content-Type: text/html;charset=EUC-KR
< Content-Length: 0
< Date: Mon, 02 Sep 2013 14:24:53 GMT
<
* Connection #0 to host localhost left intact
This is the web.xml file:
...
<servlet>
<description></description>
<display-name>vController</display-name>
<servlet-name>vController</servlet-name>
<servlet-class>com.vc.cac.controller.vlController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>vController</servlet-name>
<url-pattern>/vController</url-pattern>
</servlet-mapping>
<listener>
<listener-class>com.vc.cac.controller.vlController</listener-class>
</listener>
...
in the servlet I tried to print the Host element from header:
String host = request.getHeader("Host");
System.out.println("Host: "+host);
but I get null, so If I try to print any header element I get null as a result. any help?
On Tomcat 7.0.22, the following servlet
#WebServlet(urlPatterns = "/vController")
public class vlController extends HttpServlet {
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException {
String host = request.getHeader("Host");
System.out.println("Host: "+host);
resp.getWriter().write("host printed");
}
}
with an index.jsp
<%# page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
<jsp:forward page="/vController" />
Heello wRoldasdas
</body>
</html>
The cURL command prints
$ clear; curl -v http://localhost:8080/
* About to connect() to localhost port 8080 (#0)
* Trying 127.0.0.1...
* 0x60002d0f0 is at send pipe head!
* STATE: CONNECT => WAITCONNECT handle 0x60006cac0; line 1032 (connection #0)
* Connected to localhost (127.0.0.1) port 8080 (#0)
* STATE: WAITCONNECT => DO handle 0x60006cac0; line 1151 (connection #0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: localhost:8080
> Accept: */*
>
* STATE: DO => DO_DONE handle 0x60006cac0; line 1236 (connection #0)
* STATE: DO_DONE => WAITPERFORM handle 0x60006cac0; line 1352 (connection #0)
* STATE: WAITPERFORM => PERFORM handle 0x60006cac0; line 1363 (connection #0)
* HTTP 1.1 or later with persistent connection, pipelining supported
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
Server: Apache-Coyote/1.1
< Set-Cookie: JSESSIONID=7694BACEC0C311357E72DCEA7574540A; Path=/; HttpOnly
Set-Cookie: JSESSIONID=7694BACEC0C311357E72DCEA7574540A; Path=/; HttpOnly
< Content-Type: text/html;charset=ISO-8859-1
Content-Type: text/html;charset=ISO-8859-1
< Content-Length: 12
Content-Length: 12
< Date: Mon, 02 Sep 2013 16:40:11 GMT
Date: Mon, 02 Sep 2013 16:40:11 GMT
<
* STATE: PERFORM => DONE handle 0x60006cac0; line 1533 (connection #0)
* Connection #0 to host localhost left intact
host printed
And the server clearly prints
Host: localhost:8080
In your case, the server responds with 302, so your servlet is never hit. I don't know where your null header is coming from.
Instead of with cURL, try with a Java HTTP client, ex. Apache's HttpClient.

Categories