Here is a task - it's necessary to generate a file based on some data from the UI side (JavaScript). The schema is pretty simple:
The UI makes an async POST HTTP request to the server and provides some JSON data:
$.ajax({ url: '/reports', type: "POST", data: JSON.stringify({...}), success: function (uuid) { window.location = "/reports/" + uuid; } });
The server receives the request, generates a file, puts it on the filesystem and returns the unique ID:
@RequestMapping(value = "/reports", method = RequestMethod.POST) public String generateReport(ReqData data) throws IOException { final String fileUuid = UUID.randomUUID(); ... //generate a report and return filename ... return fileUuid; }
The UI sides gets the unique id of the file generated and requests it:
success: function (uuid) { window.location = "/reports/" + uuid; }
The server outputs the file requested:
@RequestMapping(value = "/reports/{uuid}", method = RequestMethod.GET) public ResponseEntity<InputStreamResource> downloadReport(@PathVariable("uuid") String fileUuid) throws IOException { final String resultFileName = fileUuid + ".txt"; final Path resultFile = Paths.get(resultFileName); return ResponseEntity .ok() .header("Content-Disposition", "attachment; filename=\"" + resultFileName + "\"") .contentLength(Files.size(resultFile)) .contentType(MediaType.parseMediaType("text/plain")) .body(new InputStreamResource(Files.newInputStream(resultFile))); }
The problem starts when we consider this schema with multiple servers. If we have two instances Server_A and Server_B and a load balancer in the front of them then we need to make sure that the both requests mentioned above go to the same server. Thus sticky sessions are required. Providing an absolute path with the server specified like http://server_a/reports/123 is not a good option as we want to make all the servers unreachable from the outer world.
So what options are available to implement downloading files generated as well as avoid sticky sessions?