Feign Client Get Request HttpStatus 200 but body is null when json is very long - rest

I have an issue with my Feign client, I get the response as well when the json not containing lot of data. But when a json is very long I get 200 status inside Response Object but body is null:
#FeignClient(name = "processSvc", url = "${xxx}")
public interface ProcessClient {
#GetMapping(value = "/v1/process/{uid}", produces = "application/json")
Response readProcess(#PathVariable("uid") String uid);
}
Any proposition for resolve this issue ?

The issue was reading a response that is larger than the entire memory allocated to the current process. So, streaming the response fixed the issue by getting the body as InputStream, then convert it to String via IOUtils.toString() :
Response response = null;
String json;
try {
response = processClient.readProcess(uid);
json = IOUtils.toString(response.body().asInputStream(), Charsets.UTF_8.name());
} catch (IOException e) {
throw new RuntimeException(e);
}

Related

PUT request from Postman is not being received by Java Controller

I've written multiple REST Endpoints in my Controller [GET, POST and PUT].
GET and POST calls are working fine. But when I try to hit PUT request from Postman, my java controller is not able to receive that request. There is no error message. Response body is empty. Response code in Postman is 200, OK.
Here is my PUT Endpoint which is not able to get request from Postman:
#PutMapping(value = "/devRegistration")
public Object deviceRegistration(HttpServletRequest httpRequest,
#RequestBody(required = false) Map<String, Object> jsonBody ){
ResponseEntity<Object> response = null;
System.out.println("jsonBody = "+jsonBody);
devService.deviceRegistration(httpRequest, jsonBody);
return response;
}
Here is my GET Endpoint which is working fine:
#GetMapping(value = "/checkRegistration")
public void checkRegistration(HttpServletRequest httpRequest,
#RequestParam("appId") String appId, #RequestParam("offset") String offset ){
Map<String, Object> jsonBody = new HashMap<String, Object>();
jsonBody.put("appId", appId);
jsonBody.put("offset", offset);
service.checkRegistration(httpRequest, jsonBody);
}
Postman URL with Headers and Body for PUT request is :
https://localhost:8443/api/device/devRegistration
In Body:
app_Id : some value
offset : some value
Headers are:
RequestHeader
Content-Type
Authorization
MobileHeader
SessionToken
But, System.out.println() is not being executed in PUT Endpoint.
Let me know, if any other info. is required.
I found the answer.
Actually, I need to pass the params in the Body as raw form instead of form-data in Postman.
It worked now.

Bad Request on simple POST Request

I have broke it down to a minimum and still don't know why this happens.
I have the following method in my controller:
#RequestMapping(method = RequestMethod.POST, value = "/myGreatCall")
public String getDynamicData(#RequestBody DataRequest dr) {
return dr.toString();
}
Using the following simple class:
public class DataRequest {
private String type;
//Getters and setters here
}
Now if I try to call this, I get an error 400 as the response.
let url = window.location.protocol+"//"+window.location.host+"/myGreatCall";
let request = new XMLHttpRequest();
request.open("POST", url, true);
request.onload = function () {
console.log(request.response); //Here I read the reponse and get the error 404
};
// This is the data I send as the body
let data = JSON.stringify(
{
type: "myType"
}
);
request.setRequestHeader("Content-Type", "application/json");
request.send(data);
Now from the error I suspect that for some reason it cant map my json object into the java object, but I have no idea why.
I tested the following:
do the request without the Method Parameter, that worked
different data types in the java class
handing over a hardcoded string '{\"type\":\"myType\"}' to the #send()
Any Ideas what I might be doing wrong?
It may be down to JSON serialization. Try this:
let data = JSON.stringify(
{
"type": "myType"
}
);
Ok seems to be something weird. I dont know what caused it, but after a PC restart it worked fine.

Headers in POST in Grails 3 app are not being sent with rest of service

Using Grails 3.0.9, and grabbing the freshest REST API with this snippet in gradle.build:
compile 'org.grails:grails-datastore-rest-client:4.0.7.RELEASE', {
['commons-codec', 'grails-async', 'grails-core',
'grails-plugin-converters', 'grails-web', 'groovy'].each {
exclude module: it
}
}
I am trying to make the following POST request:
def rest = new RestBuilder(headers:["X-LSS-Env":"devmo"], connectTimeout:10000, readTimeout:20000)
response = rest.post("http://..../..") {
accept "application/json"
contentType "application/json"
json jsonBuilder
}
Now, the POST receiver gets the json okay, give back a response okay, but this is the problem: it receives the headers as an empty map or as null!
So, what is the correct way of passing header data to the POST receiver? This is needed because the environment key X-LSS-Env could have different values, which instructs the receiver to do further routing based on it. Same with the GET request of course.
* UPDATE *
The consumer of my POST requests is actually a Java application, running on Apache Tomcat/8.0.26. The is how the service looks on the other side:
private javax.servlet.http.HttpServletRequest hsr;
#POST
#Path("/na")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response postSomething(Ggfp ggfp ){
try {
Enumeration<String> hnames = hsr.getHeaderNames();
int i = 0;
while (hnames.hasMoreElements()) {
String headerName = hnames.nextElement();
System.out.println(++i+ " headerName: " + headerName);
String val = hsr.getHeader(headerName);
System.out.println(" val: " + val);
}
String hval = hsr.getHeader("X-LSS-Env");
return Response.status(Status.OK).entity("X-LSS-Env is " + hval).build();
} catch (Exception e) {
}
}
Calling this service from Postman works, headers are identified. Calling it from the Grails app results into an empty map - like I am sending no headers!
The RestBuilder constructor never liked the way I used (or abused) it. Here is a clean way of achieving what I set out to do, with tryCatch logic if a timeout transpires.
def makePostWsr(serviceUrl, jsonBuilder) {
try {
def rest = new RestBuilder(connectTimeout:connectTimeout, readTimeout:readTimeout)
def response = rest.post("$wsUrl/$serviceUrl") {
header 'X-LSS-Env', 'devmo'
accept "application/json"
contentType "application/json"
json jsonBuilder
}
response
} catch (Exception e) {
println "== problem makePostWsr on $serviceUrl"
null
}
}

spring boot (mvc) response with different content type encoding on error

I need help with spring handling an error.
a client service is sending a request accepting two different content types - binary and json. when everything works fine I prefer communicating to my server with binary encoding to save bandwidth. but on error I would like serialise ResponseEntity to json as my binary serialiser do not know how to serialise it to binary format, plus it is better for logging, etc.
I configured instance of ResponseEntityExceptionHandler and I am handling different exceptions from that implementation. but spring always choses binary format as it is first on the accept (or produces) list.
all I get is (because spring do not know how to serialise ResponseEntity to my custom binary format. see AbstractMessageConverterMethodProcessor#writeWithMessageConverters)
org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
client sends
headers {Accept: [application/custom-binary, application/json]
server's controller is configured to
// pseudo code
#RequestMapping(method = GET, produces = {"application/custom-binary", APPLICATION_JSON_VALUE})
public BannerMetaCollection get(#RequestParam(value = "q") UUID[] q) {
if (q != null) {
return service.getAllDataWith(q);
} else {
throw new IllegalArgumentException("invalid data");
}
}
// pseudo code
public class RestExceptionResolverSupport extends ResponseEntityExceptionHandler {
#ExceptionHandler
public ResponseEntity<Object> illegalArgumentException(IllegalArgumentException ex, WebRequest request {
Object body = errorResponse()
.withCode(BAD_REQUEST)
.withDescription("Request sent is invalid")
.withMessage(ex.getMessage())
.build());
return new ResponseEntity<Object>(body, new HttpHeaders(), HttpStatus.BAD_REQUEST);
}
}
any hints?
What I do to get this to work is that a let my endpoint method return a ResponseEntity and I don't declare what content is produced in the #RequestMapping annotation. I then set the Content-type header myself before returning the response, e.g.
// pseudo code
#RequestMapping(method = GET)
public ResponseEntity<BannerMetaCollection> get(#RequestParam(value = "q") UUID[] q) {
if (q != null) {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_TYPE, "application/custom-binary");
return new ResponseEntity<>(service.getAllDataWith(q),
headers,
HttpStatus.OK);
} else {
throw new IllegalArgumentException("invalid data");
}
}

Restful URL custom authentication failing in java

This code is for getting the text from some URL which is having custom authentication as specified below.Tried with even ajax and Jquery as dataType:"jsonp" but it is also showing 401 error.
URL u;
HttpURLConnection con;
InputStream is = null;
DataInputStream dis;
String s;
try {
// u = new URL("http://q.addthis.com/feeds/1.0/trending.json?pubid=atblog");
u = new URL("http://m2mportal.connectm.com/EMS/rest/device");
is = u.openStream();
con=(HttpURLConnection) u.openConnection();
con.connect();
con.setDoOutput(true);
con.setRequestMethod("GET");
con.setRequestProperty("Accept","application/json");
con.setRequestProperty("Authorization","authenticate\":{\"userName\":\"admin01\",\"password\":\"admin01$\",\"appId\":\"123\"}");
con.setRequestProperty("userName","admin01");
con.setRequestProperty("password","admin01$");
con.setRequestProperty("appId","123");
dis = new DataInputStream(new BufferedInputStream(is));
while ((s = dis.readLine()) != null)
{
System.out.println(s);
}
}
catch (MalformedURLException mue)
{
System.out.println("Ouch - a MalformedURLException happened.");
mue.printStackTrace();
System.exit(1);
}
catch (IOException ioe)
{
System.out.println("Oops- an IOException happened.");
ioe.printStackTrace();
System.exit(1);
}
catch(IllegalStateException ise)
{
System.out.println("In IllegalState Exception........");
ise.printStackTrace();
}
When tried to authenticate against a url which is having some custom authentication as shown in the code it is returning 401 error
Oops- an IOException happened.
java.io.IOException: Server returned HTTP response code: 401 for URL: some url
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1625)
at java.net.URL.openStream(URL.java:1037)
at com.techm.JavaGetUrl.main(JavaGetUrl.java:16)
Java Result: 1
Actually problem here is Authorization property that you passed is not encoded.
You need to pass it to Base64 encoder so that http Authorization mechanism will use it.
Base64 encoding is commonly used when there is a need to encode / decode binary data stored and transferred over network.
Add encoding to your code . change your code to :
you need to use
Base64.encodeToString()
to perform encoding.
Following link will help you more:
http://www.javatips.net/blog/2011/08/how-to-encode-and-decode-in-base64-using-java