【报错解决】The Unicode character [进] at code point [36,827] cannot be encoded as it is outside the permitted range of 0 to 255

读取文件的时候报错

: The HTTP response header [Content-Disposition] with value [attachment; filename="进度(导入模板).xlsx.xlsx"] has been removed from the response because it is invalid

java.lang.IllegalArgumentException: The Unicode character [进] at code point [36,827] cannot be encoded as it is outside the permitted range of 0 to 255

image

AI 解答

从错误信息来看,问题是由于HTTP响应头Content-Disposition中的文件名包含了非ASCII字符(中文字符“进”),而Tomcat服务器尝试将这个值转换为字节数组时失败了。因为Unicode字符“进”的代码点是36,827,超出了单字节表示的0到255的范围,所以导致了IllegalArgumentException

要解决这个问题,可以采取以下几种方法之一:

  1. URL编码:对Content-Disposition头中的文件名进行URL编码,确保所有非ASCII字符都被正确地转义。例如,使用URLEncoder.encode()方法来编码文件名部分。

  2. RFC 5987兼容性:遵循RFC 5987规范,它允许在HTTP头部中使用UTF-8编码的参数值。你可以构建一个符合该规范的Content-Disposition头,比如:

    Content-Disposition: attachment; filename*=UTF-8''%E8%BF%9B%E5%BA%A6%EF%BC%88%E5%AF%BC%E5%85%A5%E6%A8%A1%E6%9D%BF%EF%BC%89.xlsx
    
  3. 设置正确的字符集:确保你的应用服务器配置支持UTF-8编码。对于Tomcat,可以在server.xml中配置Connector元素的URIEncoding属性为UTF-8,以确保所有的URI被正确地解码。

  4. 使用简单的文件名:如果可能的话,避免在文件名中使用非ASCII字符,采用仅包含ASCII字符的简单文件名。

以下是使用RFC 5987格式的示例代码,假设你正在使用Spring框架:

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.nio.charset.StandardCharsets;
import java.net.URLEncoder;
import java.util.Objects;

@RestController
public class FileDownloadController {

    @GetMapping("/download")
    public ResponseEntity<byte[]> downloadFile() {
        String filename = "进度(导入模板).xlsx";
        byte[] fileContent = {/* ... 文件内容 ... */};

        // 使用RFC 5987格式编码文件名
        String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8)
                .replaceAll("\\+", "%20");

        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, 
            "attachment; filename=\"" + filename + "\"; filename*=UTF-8''" + encodedFilename);

        return new ResponseEntity<>(fileContent, headers, HttpStatus.OK);
    }
}

这段代码确保了Content-Disposition头部能够正确处理包含非ASCII字符的文件名,并且应该能避免你遇到的异常。请根据你的具体环境和需求调整解决方案。

应用代码

    @Override
    public ResponseEntity<Resource> getFileObj(String fileMd5) {
        List<SystemFile> systemFiles = fileMapper.getFileByMd5(fileMd5);
        if (systemFiles.isEmpty()) {
            return ResponseEntity.notFound().build();
        }
        SystemFile systemFile = systemFiles.get(0);
        String realAddress = configMapper.getKeyValue(SystemConfigKey.SYS_FILE_SAVE_PATH)+systemFile.getPath(); // 真实的文件存储地址
        log.info("真实文件地址:{}", realAddress);
        Resource resource = new FileSystemResource(realAddress);

        if (resource.exists() && resource.isReadable()) {
//            return ResponseEntity.ok()
//                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + systemFile.getFileName()+systemFile.getFileType() + "\"")
//                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
//                    .body(resource);
            // 使用RFC 5987格式编码文件名
            String encodedFilename = URLEncoder.encode(systemFile.getFileName(), StandardCharsets.UTF_8)
                    .replaceAll("\\+", "%20");
            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + systemFile.getFileMd5()+systemFile.getFileType()+ "\"; filename*=UTF-8''" + encodedFilename)
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .body(resource);
        } else {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
        }
    }
posted @ 2024-12-30 15:44  萌狼蓝天  阅读(25)  评论(0编辑  收藏  举报