RestTemplate UTF-8 encoding with exchange not working - java

I am using exchange method of RestTemplate as below but it doesn't encode some characters right.
Original value is : <Description>Salih'in firewallişççöı ımçööşöşöğ</Description>
Sent value is:<Description>Salih'in firewalli?���? ?m���?�?�?</Description>
Headers are as follows:
Content-Type : application/vnd.vmware.admin.edgeGatewayServiceConfiguration+xml; charset=ISO-8859-1
Accept : application/*+xml;version=5.6
This is how i make the request
restTemplate.setErrorHandler(new RequestErrorHandler());
restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
apiResponse = restTemplate.exchange(url, vCloudRequest.getHttpMethod(), entity, responseType);

The problem was that RestTemplate was using charset=ISO-8859-1 which is given in the Content-Type header.
It is checking the Content-Type header if any charset is specified and if so it uses that charset.

Related

Spring WebClient BodyInserters.fromResource() changes content-type?

I'm new to Spring's WebClient. I'm trying to post the contents of a file using the content-type application/octet-stream. Initially I loaded the contents of the file into a byte array and used .bodyValue() to add it. This works perfectly.
byte[] data;
// read file into byte array here ...
FileUploadResponse resp = client.post().uri(uri)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.accept(MediaType.APPLICATION_JSON)
.bodyValue(data) // From byte[]
.retrieve()
.bodyToMono(FileUploadResponse.class)
.block();
Obviously loading the entire contents of the file into memory is not great. So I did a little searching and it looks like I need to use a "from resource body inserter." So I changed the code to this:
// Use a Spring FileSystemResource that will be used to insert the data into the body.
FileSystemResource resource = new FileSystemResource(localFilename);
// Create a web client
WebClient client = WebClient.create();
FileUploadResponse resp = client.post().uri(uri)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.accept(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromResource(resource)) // From file resource
.retrieve()
.bodyToMono(FileUploadResponse.class)
.block();
Now the content-type is being sent as "text/plain" (see below)
POST /fileupload
accept-encoding: gzip
user-agent: ReactorNetty/0.9.11.RELEASE
host: localhost:8080
Content-Type: text/plain
Accept: application/json
What am I doing wrong? Does the BodyInserters.fromResource() always override the content-type to "text/plain"? Is there some other way I should be doing this?
Thank you!
It happens because of the specific handling of the application/octet-stream in ResourceHttpMessageWriter. It tries to detect mime type by file extension.
You could use InputStreamResource instead to keep application/octet-stream
var resource = new InputStreamResource(new FileInputStream(localFilename));

Update default Content-Type for multipart form-data request in Android

We are currently using okhttp3 and retrofit2 in Android to make an network api call of type POST with multipart/form-data, the api request and response are as shown below
If you observe, the request header Content-Type has "multipart/form-data; boundary=xxxxxx-xxxx-xxx...."
Following is the code
#Multipart
#POST("/some-api-method")
Call<SomeResponseBody> someCreateMethod(#PartMap Map<String, RequestBody> options);
I'm facing an issue with sending the customised request header Content-Type as "multipart/form-data; **charset=utf-8;** boundary=xxxxx-xxxxx-x....."
basically i need to update the Content-Type header to accommodate "charset=utf-8;"
For this i tried following code
#Multipart
#POST("/some-api-method")
#Headers({
"Content-Type: multipart/form-data; charset=utf-8"
})
Call<SomeResponseBody> someCreateMethod(#PartMap Map<String, RequestBody> options);
This resulted in addition of "charset=utf-8;" to Content-Type, but this resulted in removal or non addition of existing attribute "boundary=xxx-xxxx.....;"
basically i need something like below
Content-Type : "multipart/form-data; charset=utf-8; boundary=xxxx-xxx.....;"
Any help here to achieve this will be appreciated.
Thanks to
Retrofit - Multipart request: Required MultipartFile parameter 'file' is not present
&
https://stackoverflow.com/a/51647665/932044
these pointed me in the right direction and i have fixed my issue in the following way
#POST("/some-api-method")
Call< SomeResponseBody > someCreateMethod(#Header("Content-Type") String contentType, #Body RequestBody body);
I created the MultipartBody object as below
RequestBody dataBody = RequestBody.create(okhttp3.MultipartBody.FORM, mGson.toJson(mData));
MultipartBody multipartBody = new MultipartBody.Builder()
.addPart(MultipartBody.Part.createFormData("key1", null, requestBodyObj1))
.addPart(MultipartBody.Part.createFormData("key2", null, requestBodyObj2))
.addPart(MultipartBody.Part.createFormData("key3", null, dataBody))
.build();
String contentType = "multipart/form-data; charset=utf-8; boundary=" + multipartBody.boundary();
someCreateMethod(contentType, multipartBody);

Spring RestTemplate GET request returns 302 status

I am trying to consume a third party REST API using Spring's RestTemplate component. I have tried entering the same request on an external REST API Client (Postman) - using the same URI and custom headers and I am able to retrieve the correct data.
However, when I tried to mirror the exact request using RestTemplate, it returns me
<html><head>
<title>302 Found</title>
</head><body>
<h1>Found</h1>
<p>The document has moved here.</p>
<hr>
<address>Apache/2.4.7 (Ubuntu) Server at address Port 80</address>
</body></html>
This is a sample of the code I am using:
String uri = "http://address/{path of endpoint}";
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set(someCustomHeaderKey, someCustomHeaderValue);
HttpEntity<String> entity = new HttpEntity<String>(headers);
ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);
I have read that java does not allow redirect from one protocol to another, for instance, from http to https and vise versa. Would require some help on the approach on this.
RestTemplate will follow redirects by default, but not if the protocol is different,
which is the situation that you are seeing (redirecting from http to https).
For a more full explanation, and code that makes this work, see
HTTPURLConnection Doesn't Follow Redirect from HTTP to HTTPS
I have tried your code on my local machine and everything seems fine.
302 status code is indicating that your URI location is different.
as per your example, you should use https instead of Http in URI
I have tried your code as below
String uri = "https://jsonplaceholder.typicode.com/todos/1";
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("link", "http/:");
HttpEntity<String> entity = new HttpEntity<String>(headers);
ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET,
entity, String.class);
System.out.println(response);
output in console
<200,{
"userId": 1,
"id": 1,
"title": "delectus aut autem",
"completed": false
},[Date:"Thu, 12 Mar 2020 03:45:44 GMT", Content-Type:"application/json; charset=utf-8", Content-Length:"83", Connection:"keep-alive", Set-Cookie:"__cfduid=d3104b8bbd25cbcb802977fc9183d559e1583984744; expires=Sat, 11-Apr-20 03:45:44 GMT; path=/; domain=.typicode.com; HttpOnly; SameSite=Lax", X-Powered-By:"Express", Vary:"Origin, Accept-Encoding", Access-Control-Allow-Credentials:"true", Cache-Control:"max-age=14400", Pragma:"no-cache", Expires:"-1", X-Content-Type-Options:"nosniff", Etag:"W/"53-hfEnumeNh6YirfjyjaujcOPPT+s"", Via:"1.1 vegur", CF-Cache-Status:"HIT", Age:"1747", Accept-Ranges:"bytes", Expect-CT:"max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"", Server:"cloudflare", CF-RAY:"572a862eab83d5e8-BOM"]>

How is HTTP Header set in Spring RestTemplate?

I wanted to get the plain string, not JSON. The code at client side:
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.TEXT_PLAIN));
HttpEntity<String> entity = new HttpEntity<String>("", headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> tickerResponse = restTemplate.exchange(serviceBase, HttpMethod.GET, entity,String.class);
It works well in local unit test. The log looks like:
08:24:46,291 DEBUG RestTemplate:598 - Setting request Accept header to
[text/plain, /]
However, it doesn't work in tomcat, the log was:
08:20:48,362 DEBUG RestTemplate:598 - Setting request Accept header
to [application/json, application/*+json, text/plain, /]
I guess RestTemplate set the Accept Header to JSON by default when running in my Tomcat 8. How to clean the default settings?

Jersey Client set content-type header as text/plain

Using jersey client sending HTTP request. Content-Type header is automatically set as "application/json" (as a nature), but i want to changing "content-type" header with "text/plain" regardless of any specification, standards etc. Jersey version is 2.4.1.
Code
String target = "http://192.168.1.2:10000";
String path = "test3";
Client c = ClientBuilder.newClient ();
WebTarget target = c.target (target).path (path);
Entity<SubscriberBean> json = Entity.json (subscriber);
Builder request = target.request ();
String response = request.post(json, String.class);
Request
POST /test3 HTTP/1.1
Accept: text/html
Content-Type: application/json
User-Agent: Jersey/2.4.1 (HttpUrlConnection 1.6.0_17)
Host: 192.168.1.2:10000
Connection: keep-alive
Content-Length: 278
///**** Some json data ***///
instead of
request.post(json, String.class);
try to use
request.type(MediaType.TEXT_PLAIN).post(json, String.class);
Use Entity.text(entityData) or Entity.entity(entityData, mediaType) methods instead of Entity.json() in your example.

Categories