I want to return file with Cyrillic name.
Now my code looke like:
@GetMapping("/download/{fileId}")
public void download(@PathVariable Long fileId, HttpServletResponse response) throws IOException {
...
response.setContentType("txt/plain" + "; charset=" + "WINDOWS-1251");
String filename = "русское_слово.txt";
response.addHeader("Content-disposition", "attachment; filename=" + filename);
response.addHeader("Access-Control-Expose-Headers", "Content-disposition");
//...
}
When I access url from browser - browser provides me dialog to save file on disk but it show _
instead of Cyrillic symbols.
Looks like it is response header encoding issue:
{
"access-control-expose-headers": "Content-disposition",
"content-disposition": "attachment; filename=???_??.txt",
"date": "Fri, 28 Dec 2018 15:53:44 GMT",
"transfer-encoding": "chunked",
"content-type": "txt/plain;charset=WINDOWS-1251"
}
I tried following option:
response.addHeader("Content-disposition", "attachment; filename*=UTF-8''" + filename);
and following:
response.addHeader("Content-disposition", "attachment; filename*=UTF-8''" + URLEncoder.encode(filename,"UTF-8"));
but it doesn't help
How can I fix this issue?
If you're on Spring 5+ you can use ContentDisposition
:
String filename = "русское слово.txt";
ContentDisposition contentDisposition = ContentDisposition.builder("attachment")
.filename(filename, StandardCharsets.UTF_8)
.build();
System.out.println(contentDisposition.toString());
Output:
attachment; filename*=UTF-8''%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%BE%D0%B5%20%D1%81%D0%BB%D0%BE%D0%B2%D0%BE.txt
The ContentDisposition
hides all the work you're trying to do (see its toString
implementation):
if (this.filename != null) {
if (this.charset == null || StandardCharsets.US_ASCII.equals(this.charset)) {
sb.append("; filename=\"");
sb.append(this.filename).append('\"');
}
else {
sb.append("; filename*=");
sb.append(encodeHeaderFieldParam(this.filename, this.charset));
}
}
Also if you don't want to deal with HttpServletRequest
directly you can return ResponseEntity
instead:
@RequestMapping("/")
public ResponseEntity<Resource> download() {
HttpHeaders httpHeaders = new HttpHeaders();
String filename = "русское_слово.txt";
ContentDisposition contentDisposition = ContentDisposition.builder("attachment")
.filename(filename, StandardCharsets.UTF_8)
.build();
httpHeaders.setContentDisposition(contentDisposition);
return new ResponseEntity<>(new ByteArrayResource(new byte[0]),
httpHeaders, HttpStatus.OK);
}