下载文件保留原始中文文件名

需求

下载文件时,需要保留原始中文文件名称

实现

  • 文件名:中文文件名.txt
  • 使用URLEncoder.encode之后的文件名:%E4%B8%AD%E6%96%87%E6%96%87%E4%BB%B6%E5%90%8D.txt
  • 代码实现:
fun downloadFile(
    bytes: ByteArray,
    fileName: String,
    mediaType: String = MediaTypes.APPLICATION_BINARY,
) {
    
    
  val response = (RequestContextHolder.getRequestAttributes() as ServletRequestAttributes).response!!
  response.contentType = mediaType
  // 先将文件名编码
  val encodeFileName = URLEncoder.encode(fileName, "UTF-8")
  // 再传入响应头中,主要是:fileName*=UTF-8''$encodeFileName,接下来的事情交给浏览器
  // UTF-8 指定你使用的编码方式,encodeFileName为你编码后的文件名
  response.setHeader(
    FileUploadBase.CONTENT_DISPOSITION, "attachment;fileName*=UTF-8''$encodeFileName"
  )
  response.outputStream.write(bytes)
}

原理

filename* 是 Content-Disposition 响应头域的一个扩展,用于在 HTTP 响应中指定一个 Unicode 文件名,并支持使用 RFC 5987 规定的方式来指定文件名,并支持 UTF-8 编码的中文字符。相比之下,filename 字段只支持 ASCII 字符,因此无法直接在其中指定中文文件名。

在 HTTP/1.1 中,filename* 字段的语法定义如下:

Content-Disposition: attachment; filename*=charset'lang'encoded-value

其中,charset 是指定编码的字符集,lang 是指定语言的 ISO 639-1 编码,encoded-value 是指定文件名的编码值。RFC 5987 规定将 encoded-value 编码为 ASCII 字符集的百分比编码,然后将其嵌入到 filename* 字段中。

在实际应用中,通常使用 UTF-8 编码和语言编码为英语(en)来指定文件名。例如,以下是一个 filename* 字段的示例:

Content-Disposition: attachment; filename*=UTF-8''%E4%B8%AD%E6%96%87%E6%96%87%E4%BB%B6%E5%90%8D.txt

在这个示例中,文件名为 “中文文件名.txt”,使用 UTF-8 编码进行 URL 编码,然后将编码后的值 %E4%B8%AD%E6%96%87%E6%96%87%E4%BB%B6%E5%90%8D.txt 嵌入到 filename* 字段中。

需要注意的是,filename* 字段只是 Content-Disposition 响应头的一个扩展,因此并不是所有的浏览器和下载工具都支持它。如果浏览器或下载工具不支持 filename* 字段,则会尝试使用 filename 字段来保存文件,此时需要将文件名进行 URL 编码,以确保兼容性。

猜你喜欢

转载自blog.csdn.net/wwrzyy/article/details/131551562
今日推荐