通过 REST API 上传多部分文件会损坏文件并增加文件大小

Posted

技术标签:

【中文标题】通过 REST API 上传多部分文件会损坏文件并增加文件大小【英文标题】:Multipart File Upload via REST API corrupts file and increases file size 【发布时间】:2017-01-30 05:41:45 【问题描述】:

我正在从 Postman 或应用程序 UI 将文件(任何格式的 doc、docx、pdf、文本等)作为多部分表单/数据上传到 REST API。文本文件上传正常。所有其他非文本格式都会损坏。我打不开那些文件。

上传文件的大小急剧增加。检查以下服务器日志:

File size just before call to request.getRequestDispatcher().forward(): 27583
Controller, first line in method:39439

上传文件大小为27.3Kb

我猜是因为附加到文件的其他数据导致文件损坏。

控制器方法是

@RequestMapping(value="/entity/entity/entityId/type/type/derive",method = RequestMethod.POST)
    @ResponseBody
    public String uploadFile(@RequestParam("file") MultipartFile multipartFile,@PathVariable("entity")String entity,@PathVariable("type")String type,@PathVariable("entityId")Long entityId,@PathVariable("derive") boolean derive) throws Exception

由于文本文件保存正确,其他文件也正确写入,请不要认为写入文件的代码不正确。

获取输入流的代码

public String storeFile(MultipartFile multipartFile, String entity, Long id, String uploadType, boolean isDerive,String customName)
                                                                                                                     throws Exception
    
        try
        
            System.out.println(multipartFile.getSize());
            String fileName = "";
            String contentType = "";
            if (multipartFile != null)
            
                fileName = multipartFile.getOriginalFilename();
                contentType = multipartFile.getContentType();
                if (contentType == null)
                
                    contentType = "application/msword";
                
            
            InputStream is = multipartFile.getInputStream();
            String filePath = getFileName(entity, uploadType, id, fileName, isDerive,customName);
            Helper.storeFile(is, filePath);
            precedingPath = precedingPath.length() > 0 ? precedingPath + "/":"";
            return precedingPath + filePath;
        
        catch (WebException e)
        
            e.printStackTrace();
            throw e;
        
        catch (Exception e)
        
            e.printStackTrace();
            throw new WebException(e.getMessage(), IHttpConstants.INTERNAL_SERVER_ERROR, e);
        
    

Helper.storeFile

public static File storeFile(InputStream is, String filePath) throws IOException 
        try 
            String staticRepoPath = null;

            if (MasterData.getInstance().getSettingsMap().containsKey(Settings.REPO_LOCATION.toString())) 
                staticRepoPath = MasterData.getInstance().getSettingsMap().get(Settings.REPO_LOCATION.toString());
             else 
                throw new WebException("Invalid Settings");
            

            byte[] buffer = new byte[is.available()];
            is.read(buffer);

            File targetFile = new File(staticRepoPath + File.separator + filePath);
            @SuppressWarnings("resource")
            OutputStream outStream = new FileOutputStream(targetFile);
            outStream.write(buffer);
            return targetFile;
         catch (Exception e) 
            e.printStackTrace();
        
        return null;
    

我的ajax请求如下

var fd = new FormData();
//Take the first selected file
fd.append("file", document.actualFile);
//Generic AJAX call
CandidateService.ajax_uploadDocumentWithDocType($scope.candidate.id, fd, document.docType, function (error, json)

上传时的内容类型:

 var config = headers:'X-Auth-Token':authToken, 'Content-Type': undefined, transformRequest: angular.identity;

有人知道我该如何解决这个问题并成功上传文件吗?

Q1) 为什么请求调度程序和处理文件数据的控制器之间的文件大小会发生变化。

Q2) 文件大小的这种变化是否会导致文件损坏? Libre Office 导致一般输入/输出错误。

【问题讨论】:

不知道为什么有人标记为-1。我已经使用这个 api 超过 1 年了。自过去 3 个月以来,文件在上传时已损坏。通过 git history 彻底检查了我的代码。无法弄清楚发生了什么变化。因此更深入地检查文件大小等。上面更新的 API 调用 您是否尝试过使用其他 API? 我没有投反对票,但你没有发布代码。没有办法知道你在用 MultipartFile 做什么。 已添加我的代码。 user1478061:还有哪些 API?此 REST API 适用于文本文件。其他二进制文件也被上传。但我无法打开上传的文件。它在 Libre Office 中给出一般输入/输出错误。 pdf文件也打不开。在 Spring 请求调度程序和控制器调用之间,我没有做任何其他事情。 【参考方案1】:

我发现了文件上传的问题。我中间有一个弹簧过滤器,它将请求更改为wrappedRequest。这是向多部分数据添加额外数据并导致文件损坏。

【讨论】:

您是否有更多信息?我们在一个基本的 springboot 应用程序中遇到了同样的问题。 没有。没有更多信息。在调用控制器之前运行的弹簧过滤器给我们带来了问题。 Sonal,您能否解释一下您在控制器或过滤器中为解决此问题所做的更改,我也遇到了完全相同的问题并使用了安全过滤器。 确认 springSecurityFilterChain 仅在 docx、pdf 的情况下损坏多部分文件,删除它们可以解决问题。授权过滤器不会导致任何问题,浪费了将近 2 天的时间来找到这个解决方案 @Sonal,感谢您分享这个想法,自过去 2-3 天以来,我遇到了同样的问题并且正在为损坏的文件而苦苦挣扎。你的想法对我帮助很大。谢谢:)【参考方案2】:

在我的情况下,我在通过 Amazon API Gateway 访问 API 时遇到了同样的问题。结果我忘了在 API Gateway 上允许多部分 ContentType。 有点奇怪,请求仍然发送到我的服务器,并且文本文件运行良好。

【讨论】:

你能分享一下你是如何在 API Gateway 上允许多部分 ContentType 的吗?

以上是关于通过 REST API 上传多部分文件会损坏文件并增加文件大小的主要内容,如果未能解决你的问题,请参考以下文章

ASPNetCore - 通过 REST 上传文件

快速文件上传java rest api mimepull关闭问题与多部分表单数据

Grails JAX-RS REST 多部分文件上传

Onedrive Upload API 上传损坏的文件或图像

如何使用 JMeter 使用 REST API Put 方法上传文件

通过Google Drive REST API上传或创建包含内容的新文件?