I have developed a Spring MVC project providing REST. One of the methods returns a zip file of data. If the data packet is small (under 10MB) or we receive few connections the response time is ok, but if I have a 20MB file or a hundred of requests, it is slow. This is my code:
@RequestMapping(value = "{venue}/packet", method = RequestMethod.GET)
public ResponseEntity getPackage(@PathVariable("venue") int id,
@RequestParam(value = "reqid", required = false) int reqid,
@RequestParam(value = "version", required = false, defaultValue = "1.0") String version,
@ModelAttribute("user") Developer user, HttpServletRequest request, HttpServletResponse resp) {
String req_code = "[" + Thread.currentThread().getId() + "] ";
long start = System.currentTimeMillis();
// Check if the version of the client is already updated
if (!version.equals(venue.getVersion())) {
//Returns a file from File System
File zipped = venueService.getPacket(venue);
resp.setContentType("application/zip");
resp.setContentLength((int) zipped.length());
resp.setHeader("Content-Disposition", "attachment;filename=" + zipped.getName());
try {
InputStream is = new BufferedInputStream(new FileInputStream(zipped));
long copytime = System.currentTimeMillis();
packet_log.info(req_code + "Start copy req:" + reqid);
IOUtils.copy(is, resp.getOutputStream());
resp.flushBuffer();
is.close();
packet_log.info(req_code + "End copy req:" + reqid + " in " + (System.currentTimeMillis() - copytime));
} catch (IOException e) {
e.printStackTrace();
}
long dur = System.currentTimeMillis() - start;
packet_log.info(req_code + "Send to client req:" + reqid + " in " + dur / 1000);
packet_log.info("");
return new ResponseEntity<Object>("", headers, HttpStatus.OK);
}
I have inserted a lot of logs and a "reqid" parameter, shared by client and server, to monitor every request. When I have multiple concurrent request the command IOUtils.copy(is, resp.getOutputStream());
become very slow. If I send 80 requests it takes even more then a minute to copy a 20MB file.
I don't think there is a problem on my code. Maybe it depends on how Spring MVC manages @RestController beans? Or is a I/O problem of access to disk? The system is on a AWS EC2 virtual machine.
What you have implemented is a Blocking way to download files by Directly writing to the HttpServletResponse
's OutputStream
.
If you are using Spring 4.2+ you can return a StreamingResponseBody
which will Asynchronously stream the File bytes to the receiving client.
Instead of using IOUtils.copy(is, resp.getOutputStream());
to copy input stream of file to HttpServletResponse
's output stream use FileSystemResource
to dowload your zip file at client end.
public FileSystemResource downloadFile(HttpServletResponse response) {
File file = new File("BASE_PATH/MY_ZIP_FILE.zip");
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename="+"MY_ZIP_FILE.zip");
return new FileSystemResource(file);
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.