I've got a simple web-service that stream a file using a StreamingResponseBody.
The definition looks like this:
#GetMapping("/files/{filename}")
public ResponseEntity<StreamingResponseBody> download(#PathVariable String filename) {
...
StreamingResponseBody responseBody = out -> {
...
}
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentLength(byteArray.length);
return new ResponseEntity(responseBody, httpHeaders, HttpStatus.OK);
}
It works well, but now, I need to consume it in a client application.
I'm using spring to consume it, but I can't find a way to read the stream and write it to a file as it flows...
I tryied using feign but it seems it doesn't support it.
I tryied using restTemplate but I can't make it work...
Does spring support streaming client side ?
Does anybody know how to do this ?
Perhaps using pure java API ?
Thanks a lot for your help !
You can use Apache Http Client (org.apache.httpcomponents:httpclient:4.5.12):
URI uri = new URIBuilder()
.setScheme(scheme)
.setHost(host)
.setPort(port)
.setPath(url)
.build();
HttpUriRequest request = RequestBuilder.get(uri).build();
try (CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse httpResponse = httpClient.execute(request);
InputStream inputStream = httpResponse.getEntity().getContent()) {
// Do with stream whatever you want, for example put it to File using FileOutputStream and 'inputStream' above.
}
Related
I'm currently trying to build an OSGi service that sends a POST request to a defined API. This API is used to virus-scan a file which is contained in the request body (JSON) as Base64 string.
For this, I am using Apache HttpClient contained in Adobe AEM uberjar v6.4.0
My current implementation works fine for smaller files (<2 MB), but as filesize gets bigger, the behaviour gets strange:
When I upload a 9 MB file, the request executes for ~1 minute, then gets a HTTP400 as response and afterwards retrys the request 7 times.
I tried to use a timeout with the request. If the timeout is below 60.000ms, a TimeoutException is thrown, if it's greater than 60.000ms, I get a HTTP400 Bad Request. I guess the latter is the APIs fault which I need to clarify.
However, in both cases after the exception is thrown, httpClient retries the request and I have not been able to prevent that since. I'm struggeling with many deprecated "HowTo's" on the web and now I'm here.
I have shortened the code a bit, as it's somehow big (mostly removing debug messages and some "if... return false" at the beginning). My Code:
public boolean isAttachmentClean(InputStream inputStream) throws IOException, JSONException, ServiceUnavailableException {
//prevent httpClient from retrying in case of an IOException
final HttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(0, false);
HttpClient httpClient = HttpClients.custom().setRetryHandler(retryHandler).build();
HttpPost httpPost = new HttpPost(serviceUrl);
httpPost.setHeader("accept", "application/json");
//set some more headers...
//set timeout for POST from OSGi Config
RequestConfig timeoutConfig = RequestConfig.custom()
.setConnectionRequestTimeout(serviceTimeout)
.setConnectTimeout(serviceTimeout)
.setSocketTimeout(serviceTimeout)
.build();
httpPost.setConfig(timeoutConfig);
//create request body data
String requestBody;
try {
requestBody = buildDataJson(inputStream);
} finally {
inputStream.close();
}
HttpEntity requestBodyEntity = new ByteArrayEntity(requestBody.getBytes("UTF-8"));
httpPost.setEntity(requestBodyEntity);
//Execute and get the response.
HttpResponse response = httpClient.execute(httpPost);
if (response.getStatusLine().getStatusCode() != HttpServletResponse.SC_OK){
httpPost.abort();
throw new ServiceUnavailableException("API not available, Response Code was "+ response.getStatusLine().getStatusCode());
}
HttpEntity entity = response.getEntity();
boolean result = false;
if (entity != null) {
InputStream apiResult = entity.getContent();
try {
// check the response from the API (Virus yes or no)
result = evaluateResponse(apiResult);
} finally {
apiResult.close();
}
}
return result;
}
"buildDataJson()" simply reads the InputStream and creates a JSON needed for the API call.
"evaluateResponse()" also reads the InputStream, transforms it into a JSON and checks for a property named "Status:" "Clean".
I'd appreciate any tipps on why this request is retried over and over again.
/edit: So far, I found that Apache httpClient has some default mechanism that retries a request in case of an IOException - which is what I get here. Still, I have not found a solution on how to deactivate these retries.
I've installed BIRT Web-Viewer on my server and am able to build the report with this URL:
http://hostname:port/birt/run?__report=test.rptdesign
Now I need to programmatically call this URL from my Java Code and retrieve the result as stream or file.
Is there any API for the Web-Viewer?
If not, could I just call the URL like this and extract the PDF?:
HttpClient httpClient = HttpClients.createDefault();
HttpGet postRequest = new HttpPost("http://hostname:port/birt/run");
List<NameValuePair> formData = new ArrayList<>();
formData.add(new BasicNameValuePair("__report", "test.rptdesign"));
HttpEntity entity = new UrlEncodedFormEntity(formData);
HttpResponse response = httpClient.execute(postRequest);
I found out, if I use the __format parameter with the value pdf, the response to the request is the PDF content, which is exactly what I wanted.
The standard response is a HTML, which will be returned with a second request. I'm pretty sure that response has to be retrieved with sessions.
Edit:
As requested I will post my request code. I modified it a bit, because I used some custom classes to hold configuration and the report.
public InputStream getReport() throws Exception {
StringBuilder urlBuilder = new StringBuilder()
.append("http://example.com:9080/contextRoot/run")
.append("?__report=ReportDesign.rptdesign&__format=pdf");
if (reportParameters != null) {
for (Map.Entry<String, String> parameter : reportParameters.entrySet()) {
String key = StringEscapeUtils.escapeHtml(parameter.getKey());
String value = StringEscapeUtils.escapeHtml(parameter.getValue());
urlBuilder.append('&')
.append(key);
.append('=');
.append(value);
}
}
URL requestUrl = new URL(burlBuilder.toString());
HttpURLConnection connection = (HttpURLConnection) requestUrl.openConnection();
connection.setRequestMethod("GET");
connection.setDoInput(true);
connection.connect();
return connection.getInputStream();
}
I also had another method write the used data as XML to the file system before I called requestUrl.openConnection(), but I think this is only necessary if you use very dynamic data like I did.
I want to send a file via Telegram Bot API, but I don't know how should I do that in Java (posting multipart/form-data) with provided Telegram Bot HTTP API method, sendDocument.
Here is my code:
CloseableHttpClient client = HttpClients.createDefault();
HttpPost upload = new HttpPost("https://api.telegram.org/bot"+Main.token+"/sendDocument?chat_id="+id);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
File file = new File(path);
builder.addBinaryBody(
"document",
new FileInputStream(file));
HttpEntity part = builder.build();
upload.setEntity(part);
CloseableHttpResponse response = client.execute(upload);
Here are the docs.
i hope this help you.
private void sendDocUploadingAFile(Long chatId, java.io.File save,String caption) throws TelegramApiException {
SendDocument sendDocumentRequest = new SendDocument();
sendDocumentRequest.setChatId(chatId);
sendDocumentRequest.setNewDocument(save);
sendDocumentRequest.setCaption(caption);
sendDocument(sendDocumentRequest);
}
EDIT :
this pages can help any one to start coding with telegram-bot api
Telegram FAQ
a good tutorial
I'm trying to get all the headers for request/response in my logcat. Seems there is no easy way with HttpURLConnection as it is with org.apache.http.
According to this blog you can do:
sun.net.www.protocol.http.HttpURLConnection.level = ALL
Seems this was removed from Android implementation for HttpURLConnection.
Is there any easy way to sniff requests/responses on logcat?
Thanks
This is something you can easily do yourself:
private static void logConnection(HttpURLConnection httpConnection) throws IOException {
int status = httpConnection.getResponseCode();
Log.d("logConnection", "status: " + status);
for (Map.Entry<String, List<String>> header : httpConnection.getHeaderFields().entrySet()) {
Log.d("logConnection", header.getKey() + "=" + header.getValue());
}
}
Perhaps this link would help: https://stackoverflow.com/a/37525989/11845778
Though, you would still need to do the logcat part. This just gets the response as JSON.
I am not sure it is possible with standard HttpURLConnection on Android. Therefore it is easy to achieve using OkHttp library:
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
httpClientBuilder.addInterceptor(loggingInterceptor);
OkHttpClient client = httpClientBuilder.build();
Request.Builder requestBuilder = new Request.Builder();
requestBuilder.url("http://android.com");
client.newCall(requestBuilder.build()).execute();
I am trying to call a Restful JSON service using RestTemplate and Jackson json convertor. Now in order to call the service I need to pass in a Security cookie. I can achieve this by using URLConnection (See the code below)
URL url= new URL("https://XXXXXXXX");
URLConnection yc = url.openConnection();
yc.setRequestProperty("SecurityCookie", ssocookie.getValue());</code>
Whats the parallel for this in RestTemplate? Here is a code snippet which I have been using to call a Restful Service using RestTemplate:
RestTemplate rest = new RestTemplate();
InputBean input = new InputBean();
input.setResource("SampleResource");
HttpEntity<InputBean > entity = new HttpEntity<InputBean>(input);
ResponseEntity<OutputBean> response1 = rest.postForEntity(
"https://XXXXXXXXX",
entity, OutputBean.class);</code>
I can not figure out how to pass the security cookie while using RestTemplate to call the service. Any help on this would be great.
I wrote a blog post that explains how to do this using request headers:
http://springinpractice.com/2012/04/08/sending-cookies-with-resttemplate/
Here's the code:
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Cookie", "JSESSIONID=" + session.getValue());
HttpEntity requestEntity = new HttpEntity(null, requestHeaders);
ResponseEntity rssResponse = restTemplate.exchange(
"https://jira.example.com/sr/jira.issueviews:searchrequest-xml/18107/SearchRequest-18107.xml?tempMax=1000",
HttpMethod.GET,
requestEntity,
Rss.class);
Rss rss = rssResponse.getBody();
You can access the underlying HttpURLConnection used by RestTemplate by wiring your RestTemplate up with a custom ClientHttpRequestFactory, which lets you access the underlying connection to set headers, properties, etc. The ClientHttpRequestFactory is used by RestTemplate when creating new connections.
In particular, you can extend the SimpleClientHttpRequestFactory implementation and override the prepareConnection() method:
public class YourClientHttpRequestFactory extends SimpleClientHttpRequestFactory {
#Override
protected void prepareConnection(HttpURLConnection connection, String httpMethod) {
connection.setRequestProperty("SecurityCookie", ssocookie.getValue());
}
}
This is how it has worked for us
requestHeaders.add("Cookie", "JSESSIONID=" + session.getValue());