Hutool、Forest附件上传xlsx类型文件异常

一、问题背景

        最近参与某个项目对接(内容主要为我方系统提供统一界面提交数据,后端转发数据至其他系统处理),客户线上发现一个问题,就是上传了excel附件类型后,对方项目系统中迟迟未做响应,经过排查后发现在提交数据时因为附件上传失败导致后续整体调用失败(业务需要保证所有数据都成功)。

错误日志如下:

2023-11-14 16:56:40.579 -- [TID:Ignored_Trace] [http-nio-8030-exec-5] ERROR c.d.i.service.xxService.uploadFile 上传文件异常, 响应结果-{"msg":"文件类型不符, 限制上传filename: ","filename":""}

二、定位问题

        排查过程中发现,附件为图片、txt类型文件调用该接口可以正常上传,线上问题中的xlsx死活上传不了,遂与对方系统开发沟通,怀疑是上传时缺少后缀才会报,但从其他日志打印中可以明确的是这种情况并不存在,我开始怀疑是对方系统有问题,本地因对方系统白名单限制无法直接调用对方系统接口,因此想直接上服务器本地使用curl进行文件上传来验证这个问题。

curl -v -X POST -H 'token:w68sTP2t_5XeFLbPPPuJsCosadWlxbsmtl0xAtzsmhI' -F 'file=@1.xlsx' 'http://x.x.x.x/upload/'

结果依旧显示文件类型不符。

 

         将这个情况提供给对方后,但对方提供了一个点让我在  curl -F 中添加文件MIME类型再试下,居然上传成功了。

curl -v -X POST -H 'token:w68sTP2t_5XeFLbPPPuJsCosadWlxbsmtl0xAtzsmhI' -F 'file=@1.xlsx;type=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' 'http://x.x.x.x/upload/'

        

        那到此基本可以肯定的是代码中也是因为缺少这个MIME类型或者MIME类型不匹配导致对方服务器无法正常识别文件。

三、源码分析

        首先找到问题代码位置,如下显示:

import cn.hutool.http.*;

HttpResponse response = HttpRequest.post(fileOpUploadUrl)
                                    .header("ts", ts).header("token", token)
                                    .form("file",file, originalFilename)
                                    .setReadTimeout(30000)
                                    .setConnectionTimeout(3000)
                                    .execute();

        继续往下追踪:

 封装Multipart:

 

发送文件对象,并在输出流中提供文件的MIME类型

 最终定位到这边,发现是调用底层的jdk中的包去根据文件名获取MIME类型:

 

 那么底层是如何获取文件名和MIME的映射关系的呢,继续往下看,找到底层 MimeTable 类

    public synchronized void load() {
        Properties var1 = new Properties();
        File var2 = null;

        try {
            String var4 = System.getProperty("content.types.user.table");
            if (var4 != null) {
                var2 = new File(var4);
                if (!var2.exists()) {
                    var2 = new File(System.getProperty("java.home") + File.separator + "lib" + File.separator + "content-types.properties");
                }
            } else {
                var2 = new File(System.getProperty("java.home") + File.separator + "lib" + File.separator + "content-types.properties");
            }

            BufferedInputStream var3 = new BufferedInputStream(new FileInputStream(var2));
            var1.load(var3);
            var3.close();
        } catch (IOException var5) {
            System.err.println("Warning: default mime table not found: " + var2.getPath());
            return;
        }

        this.parse(var1);
    }

 至此一目了然,只需要确定这个映射文件位置即可:

打开该文件,可以发现这个映射文件涵盖了大部分类型的文件后缀(这里只截取一部分,具体支持哪些有兴趣的可以自己去看):

        但对于office相关的文件并未做过映射,因此可以根据这个判断,不止xlsx类型上传有问题,其他的office类型文件上传时一样会有这个问题。

PS:考虑到hutool有问题,联想到目前其他项目中使用的 Forest 框架是不是同样具有问题,继续查看Forest源码

往下查看2种executor如何构建附件body:

 最终进入一个共同的抽象类 AbstractBodyBuilder 类的  buildBody 方法中

进入各自实现类中,最终都会定位到相同的代码去获取MIME类型

总结:hutool和Forest工具类,在上传附件时,文件的MIME类型都是通过jdk自带的contentType的映射文件来获取的

四、解决方案

        在jdk路径下的content-types.properties中按照其他文件的映射格式,将需要补充的类型添加上去后,重启服务即可解决。

# 添加xlsx类型
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; \
    description=XLSX document;\
    file_extensions=.xlsx

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值