I have a problem getting the response body from an 403 http code response from third party server. Before april 5 2019 I was able to get the response body from third party correctly but for now I'm retrieving a byte which may not properly converted to string from getResponseBodyAsString. Is this an issue from package org.springframework.web.client?
#Autowired
RestClient restClient;
try{
//Request via restTemplate
ResponseEntity<String> responseEntity = restClient.makeClientRequestJson(batch_type.getEndpoint(), HttpMethod.POST, httpHeaders, batch_payload.getRequest(), ProcessorConstants.moduleId);
} catch (HttpClientErrorException | HttpServerErrorException ex) {
loggingService.writeLogs("Error From Third Party Request, Message: " + ex.getMessage() + "| Response Body: " + ex.getResponseBodyAsString(), this.getClass(), LoggingEnum.ERROR, BatchConstants.moduleId);
...
This is the makeClientRequestJson implementation:
public ResponseEntity<String> makeClientRequestJson(String url, HttpMethod httpMethod, HttpHeaders headers, String jsonBody , String moduleId){
RestTemplate restTemplate = new RestTemplate();
HttpEntity<String> entity = new HttpEntity<>(jsonBody, headers);
loggingService.writeLogs("Third Party Request: " + entity.getBody() + "| url: " + url + " | method: " + httpMethod.toString(), RestClientImpl.class, LoggingEnum.INFO, moduleId);
ResponseEntity<String> response = restTemplate.exchange(url, httpMethod, entity, String.class);
loggingService.writeLogs("Third Party Response: " + response.getBody() + "| url: " + url + " | method: " + httpMethod.toString(), RestClientImpl.class, LoggingEnum.INFO, moduleId);
return response;
}
the problem is when getting ex.getResponseBodyAsString() returning byte array but i get json response from server directly like:
{
"code": "403020",
"transactionID": "1555495478-1409322457-83999786",
"message": "Account is Level 1"
}
Here is sample value I get when debugging the code:
Update: This is due to the response header of the client server, some strange header on their response like connection -> close. if anyone encounter this problem be sure to scan the header responses first.
Related
I have a problem with getting a response body with a reactive spring. The service that I'm integrating with can have a different JSON body in response, so I cannot have a DTO that I can map the response to, so I was trying with String.
To check the solution for now I have mocked a simple server with SoapUi to return code 400 and JSON :
{
"errorCode" : "code",
"errorMessage" : "message"
}
and I would like to be able to log in in console in case of having an error, so here is part of my code:
.bodyValue(eventDataDto)
.exchange()
.doOnSuccess((response) -> {
if (response.rawStatusCode() != HttpStatus.OK.value()) {
throw new RuntimeException("Sending request failed with status: " + response.rawStatusCode() +
" with error message: " + response.bodyToMono(String.class);
}
})
.doOnError((throwable) -> {
throw new RuntimeException(throwable);
})
.block();
but the response that I'm getting is:
Sending request failed with status: 400 with error message: checkpoint("Body from POST http://localhost:8095/test/ [DefaultClientResponse]")
I was trying to use subscribe, map, and flatMap on that mono, but the only result was that I was getting a different class type on that error message, but nothing close to what I'm looking for.
I would appreciate any help with getting the response body in any form, that I could use its content.
EDIT WITH ANSWER:
A minute after posting it I have found a solution:
So I have tried with subscribe on mono:
.bodyValue(eventDataDto)
.exchange()
.doOnSuccess((response) -> {
if (response.rawStatusCode() != HttpStatus.OK.value()) {
Mono<String> bodyMono = response.bodyToMono(String.class);
bodyMono.subscribe(body -> {
throw new RuntimeException(
"Sending request failed with status: " + response.rawStatusCode() +
" with error message: " + body);
});
}
})
.doOnError((throwable) -> {
throw new RuntimeException(throwable);
})
.block();
I completly forgot that Mono will not give a result until subscribed.
You are receiving the proper result as your HTTP call succeeds (go-through) but returns a 400 ~ Bad Request response code which is a full concise HTTP response (which is the correct response you have configured as per your description in the OP).
In order to have the response body retrieved, either being the proper response body on a successful (200) or unsuccessful (400) response, you should use:
Either the toEntity operator
Or the bodyToMono one
Here down how your call chain would look like mapping the error response content using bodyToMono:
webClient.get()
.uri("some-uri")
.bodyValue(eventDataDto)
.exchange()
.flatMap((response) -> {
if (response.rawStatusCode() != HttpStatus.OK.value()) {
return response.bodyToMono(String.class)
.map(errorContent -> "Sending request failed with status: " + response.rawStatusCode() + " with error message: " + errorContent);
} else {
return response.bodyToMono(String.class);
})
.block();
I have a unirest response that I need to parse and it returns a string response. Kindly check the code below:
HttpResponse<String> response = Unirest.post("http://api.nuvelco.com/token")
.header("content-type", "application/x-www-form-urlencoded")
.header("cache-control", "no-cache")
.body("grant_type=password&username=" + uname + "&password=" + pword + "&client_id=paymentApp")
.asString();
I am unaware how to parse a asString() request so any help would be appreciated.
EDIT:
I forgot to include the response
{
"access_token":"HzDzAtlom6CDqRa0zPetH09hZbDr8tm__hPw7aCx2m0h0gnGwHMaKvBEp64sHRUCJJEAlhCNUqQ3tBSyvod_93gTnt145W2ly9KKw5ISmaZRN75O9NUfJUGPRd0LH87LlxiRgHNFkUGTUDwyJOmhYNajj7TQoncxqkfc3jxL-jEi3Ea1cGRvOSmLH5Aqom81kKmiRzPV_Ss0xwFWjQVsS03y_P720Hv1BQEayO9L7Vic4A64GmXm3PlFQuwcvOk3M_7WOa_EEGOFBZdhwn7dzNQ7gypJ27MSTOD3gI57880unF4XFgTT_H4p4G5V6C8L8yRbRNXPIe80gLKYk3F3nw",
"token_type":"bearer",
"expires_in":3599,
"refresh_token":"f87a5fea7d764826be24bd742626d0d8",
"as:client_id":"paymentApp",
"username":"savemore01",
".issued":"Wed, 05 Dec 2018 03:13:23 GMT",
".expires":"Wed, 05 Dec 2018 04:13:23 GMT"
}
You can use json-simple a simple Java library for JSON. So you can parse the string response value to something like that :
HttpResponse<String> httpResponse = Unirest.post("http://api.nuvelco.com/token")
.header("content-type", "application/x-www-form-urlencoded")
.header("cache-control", "no-cache")
.body("grant_type=password&username=" + uname + "&password=" + pword + "&client_id=paymentApp")
.asString();
String response = EntityUtils.toString(httpResponse.getEntity());
Object object = JSONValue.parse(response);
Note that the package of EntityUtils is org.apache.http.util
I need to get some respones from some URL.
For this purpose I use http://unirest.io/java.html and Java.
Map<String, String> map = new HashMap<>();
map.put(key1, value1);
...
map.put(keyN, valueN);
String authToken = "{token}";
HttpResponse<String> response = Unirest.post(url)
.header("Authorization","Bearer " + authToken)
.header("Content-Type", "application/json")
.fields(map)
.asString();
As a result I receive response.getStatus() = 302 and some unexpected body.
At the same time I use Postman software to get the same responses. The settings are the following:
POST: url
Authorization: Type -> Bearer Token; Token = {{authToken}} // get the value from the previous request
Header :
"Authorization" : "Bearer " + {{authToken}}
Content-Type: application/json
Body:
{
key1 : value1,
...
keyN : valueN
}
And I get some expected response.
What makes the difference?
A 302 is a redirect response. Is it possible Postman is following the redirect and returning the resultant page? Take a look at the Location header in the response you get in Java, and see if following that gives you the same results you're seeing in Postman.
I am trying to send an email using hotmail authorization access token on java env. , I have seen the documentation, but still unable to send an email successfully , here is my code :
private String doPostRequest(String accessToken) throws IOException {
MediaType JSON = MediaType.parse("application/json; charset=utf-8");
String url = "https://outlook.office.com/api/v2.0/me/sendmail";
String json = "{"+
"'Message': {"+
"'Subject': 'Meet for lunch?',"+
"'Body': {"+
"'ContentType': 'Text',"+
"'Content': 'The new cafeteria is open.'"+
"},"+
"'ToRecipients': [{"+
"'EmailAddress': {"+
"'Address': 'mymail#gmail.com'"+
"}"+
"}"+
"],"+
"'Attachments': [{"+
"'#odata.type': '#Microsoft.OutlookServices.FileAttachment',"+
"'Name': 'menu.txt',"+
"'ContentBytes': 'bWFjIGFuZCBjaGVlc2UgdG9kYXk='"+
"}"+
"]"+
"},"+
"'SaveToSentItems': 'false'"+
"}";
OkHttpClient client = new OkHttpClient();
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder().header("User-Agent", "java-tutorial").header("client-request-id", UUID.randomUUID().toString())
.header("return-client-request-id", "true").header("Authorization", String.format("Bearer %s", accessToken)).url(url).post(body).build();
Response response = client.newCall(request).execute();
System.out.println("response :"+response);
System.out.println("responseHeader :"+response.headers());
System.out.println("responseMessage :"+response.message());
return response.body().string();
}
and here is what I get on the console :
response :Response{protocol=http/1.1, code=401, message=Unauthorized, url=https://outlook.office.com/api/v2.0/me/sendmail}
responseHeader :Set-Cookie: exchangecookie=520b1dfb18d54248ba3bca9becf3a40d; expires=Mon, 29-Oct-2018 08:51:24 GMT; path=/; HttpOnly
WWW-Authenticate: Bearer client_id="00000002-0000-0ff1-ce00-000000000000", trusted_issuers="00000001-0000-0000-c000-000000000000#*", token_types="app_asserted_user_v1 service_asserted_app_v1", authorization_uri="https://login.windows.net/common/oauth2/authorize", error="invalid_token",Basic Realm="",Basic Realm="",Basic Realm=""
request-id: 7d7030b8-c31f-4572-9c18-6a2fce3609a0
client-request-id: 66b1e177-5030-4c0e-892a-7ad276351daf
X-CalculatedFETarget: AM5P190CU001.internal.outlook.com
X-BackEndHttpStatus: 401
X-FEProxyInfo: AM5P190CA0028.EURP190.PROD.OUTLOOK.COM
X-CalculatedBETarget: AM4PR05MB1906.eurprd05.prod.outlook.com
X-BackEndHttpStatus: 401
x-ms-diagnostics: 2000010;reason="ErrorCode: 'PP_E_RPS_CERT_NOT_FOUND'. Message: 'Certificate cannot be found. Certificate required for the operation cannot be found.%0d%0a Internal error: spRPSTicket->ProcessToken failed. Failed to call CRPSDataCryptImpl::UnpackData:Certificate cannot be found. Certificate required for the operation cannot be found.%0d%0a Internal error: Failed to decrypt data. :Failed to get session key. RecipientId=293577. spCache->GetCacheItem returns error.:Cert Name: (null). SKI: ee9f500e98bf0fbc492f0b138028374ec9324da4...'";error_category="invalid_msa_ticket"
X-DiagInfo: AM4PR05MB1906
X-BEServer: AM4PR05MB1906
X-FEServer: AM5P190CA0028
X-Powered-By: ASP.NET
X-FEServer: AM4PR05CA0019
X-MSEdge-Ref: Ref A: 9F523827F0CE47DEB84ECF96913B53AE Ref B: AMS04EDGE0320 Ref C: 2017-10-29T08:51:25Z
Date: Sun, 29 Oct 2017 08:51:24 GMT
Content-Length: 0
OkHttp-Sent-Millis: 1509267094755
OkHttp-Received-Millis: 1509267094903
responseMessage :Unauthorized
Note that the authorization token is correct and looks something similar to :
EwAwA8l6BAAU7p9QDpi/D7xJLwsTgCg3TskyTaQAAYDt8KR/8o7V7P+9ynPu97AHv8CIiJA/Zn+...
And it is the same one used to get the emails on inbox folder and show them to the user as what this tutorial describes .
Also I didn't forget to add the correct scopes for the api to be able to send mail "Mail.Send" .
I need to find a way to send the email successfully using authentication token , please help .
I have found a solution , looks like I need to change the url since I was calling the wrong one according to this documentation , my code now looks
public void tryingOkHttpClientPostt(String accessToken) {
OkHttpClient client = new OkHttpClient();
HttpUrl.Builder urlBuilder = HttpUrl.parse("https://graph.microsoft.com/v1.0/me/sendMail").newBuilder();
String json = "{" + "'Message': {" + "'Subject': 'Meet for lunch?'," + "'Body': {" + "'ContentType': 'Text',"
+ "'Content': 'The new cafeteria is open.'" + "}," + "'ToRecipients': [{" + "'EmailAddress': {" + "'Address': 'myMail#gmail.com'" + "}" + "}"
+ "]," + "'Attachments': [{" + "'#odata.type': '#Microsoft.OutlookServices.FileAttachment'," + "'Name': 'menu.txt',"
+ "'ContentBytes': 'bWFjIGFuZCBjaGVlc2UgdG9kYXk='" + "}" + "]" + "}," + "'SaveToSentItems': 'false'" + "}";
RequestBody body = RequestBody.create(JSON, json);
String url = urlBuilder.build().toString();
Request request = new Request.Builder().header("Content-Type", "application/json")
.header("Authorization", String.format("Bearer %s", accessToken)).method("POST", body).url(url).build();
try {
Response response = client.newCall(request).execute();
} catch (IOException e) {
e.printStackTrace();
}
}
I am creating some nodes within a transaction in neo4j using the rest api. After all nodes have been created (typically between 3 and 5 in one transaction), I have to create some relationships between them. To do this I need, of course the location of the nodes, and this is the source of my problem. I can't figure out how to get this location.
According to documentation, I should be able to get the location of a node from the response-object, after creating the node, like so:
nodeLocation = response.getLocation();
But in a transaction, this of course returns the url of the transaction:
http://localhost:7474/db/data/transaction/108
Then I thought, if I query for the just created node, maybe in that response I can find the location. Again, according to documentation, the node location should be presented in the json-structure extensions in the field self.
"self" : "http://localhost:7474/db/data/node/357",
But my response to the query does not seem to contain an extension structure.
This is the query I'm using:
{"statements": [ {"statement": "MATCH (p:POST {sn_id: 'TW', id: '536982477664190465'} ) RETURN p"} ] }
I send it to the open transaction, and I get this back:
GET to http://localhost:7474/db/data/transaction/108 returned status code 200, returned data: {"commit":"http://localhost:7474/db/data/transaction/108/commit","results":[{"columns":["p"],"data":[]}],"transaction":{"expires":"Mon, 24 Nov 2014 20:40:34 +0000"},"errors":[]}
Just for completeness, this is the code for my query:
String payload = "{\"statements\": "
+ "[ "
+ "{\"statement\": "
+ "\"MATCH (p:POST {sn_id: 'TW', id: '536982477664190465'} ) RETURN p\""
+ "} "
+ "] "
+ "}";
logger.trace("sending cypher {} to endpoint {}", payload, endpointLoc);
WebResource resource = Client.create().resource( endpointLoc );
ClientResponse response = resource
.accept( MediaType.APPLICATION_JSON )
.type( MediaType.APPLICATION_JSON )
.entity( payload )
.get(ClientResponse.class);
//.post( ClientResponse.class );
String responseEntity = response.getEntity(String.class).toString();
int responseStatus = response.getStatus();
logger.trace("GET to {} returned status code {}, returned data: {}",
endpointLoc, responseStatus,
responseEntity);
JSONParser reponseParser = new JSONParser();
Object responseObj = reponseParser.parse(responseEntity);
JSONObject jsonResponseObj = responseObj instanceof JSONObject ?(JSONObject) responseObj : null;
if(jsonResponseObj == null)
throw new ParseException(0, "returned json object is null");
String result = (String) jsonResponseObj.get("results").toString();
logger.trace("result is {} ", result);
String error = (String) jsonResponseObj.get("errors").toString();
Am I missing something? Do I need to use a special call?
Can someone help me with this? Thanks in advance,
Christian
What do you need the node-URL for?
That's the old RESTful representation. You can either get it by using the old HTTP endpoint /db/data/cypher or better by specifying the (very verbose) resultDataContents type REST
You can also specify other types like "row" and "graph" in parallel.
{"statements": [
{"statement": "MATCH (p:POST {sn_id: 'TW', id: '536982477664190465'} ) RETURN p",
"resultDataContents":["REST"]}
] }