当前位置: 首页 > 知识库问答 >
问题:

Spring Boot多部分文件上载大小不一致

颜啸
2023-03-14

我有一个endpoint,它将图像文件上传到服务器,然后上传到S3。

当我在本地主机上运行时,MultipartFile字节大小正确,并且上传成功。

然而,当我将它部署到EC2实例时,上传的文件大小不正确。

控制器代码

@PostMapping("/{id}/photos")
fun addPhotos(@PathVariable("id") id: Long,
              @RequestParam("file") file: MultipartFile,
              jwt: AuthenticationJsonWebToken) = ApiResponse.success(propertyBLL.addPhotos(id, file, jwt))

PropertyBLL.addPhotos 方法中,打印 file.size 会导致大小错误。

实际文件大小是649305字节,但是当上传到我的prod服务器时,它读取为1189763字节。

  • 我的生产服务器是一个AWS EC2实例,位于Https之后
  • Spring应用程序的yml文件是相同的。我覆盖的唯一配置是文件最大大小属性
  • 我在用邮递员把请求寄出去。我将主体作为表单数据传递,密钥名为“file”
  • 同样,当在本地运行时,它可以完美地工作

我做了另一个测试,我将上传的文件写入服务器,以便进行比较。

在十六进制编辑器中上载文件的前n个字节:

EFBFBD50 4E470D0A 1A0A0000 000D4948 44520000 03000000 02400802 000000EF BFBDCC96 01000000 0467414D 410000EF BFBD0BEFBF BD610500 00002063 48524D00 007A2600

原始文件的前n个字节:

< code > 89504 e47 0 d0a 1a 0a 00000000d 49484452 000000300 000000240 08020000 00 b5 cc 96 0100000000 0467414d 410000 B1 8f 0 bfc 61 05000000 20634852 4d 000007 a 260000000 fa 00

它们看起来都包含文本“PNG ”,并且还有结尾EXtdate:modify/create标记。

根据请求,addPhoto的核心内容如下:

val metadata = ObjectMetadata()
metadata.contentLength = file.size
metadata.contentType = "image/png"
LOGGER.info("Uploading image of size {} bytes, name: {}", file.size, file.originalFilename)
val request = PutObjectRequest(awsProperties.cdnS3Bucket, imageName, file.inputStream, metadata)
awsSdk.putObject(request)

当我在本地运行web服务器时,这一点很有效。imageName只是一个自定义生成的名称。还有其他涉及hibernate模型的代码,但并不相关。

更新

这似乎是与 Https/api 代理相关的。当我点击EC2节点的http url时,它工作正常。但是,当我通过代理到 EC2 节点的 api 代理 (https://api.thedomain.com) 时,它会失败。我将继续沿着这条路走下去。

共有3个答案

堵彬彬
2023-03-14

用于实现 Kenny Cason 解决方案的 CloudFormation 模板代码段:

  MyApi:
    Type: AWS::Serverless::Api
    Properties:
      BinaryMediaTypes:
        - "multipart/form-data"
缪阎宝
2023-03-14

抱歉,但许多评论毫无意义<代码>文件。size将返回上传文件的大小(以字节为单位),而不是请求的大小(是的,由于不同的过滤器,可能会使用其他信息和大小的增加来增强)。Spring不能只是神奇地将PNG文件的大小增加一倍(在您的情况下,在您发送的任何文件上再添加大约600kb的信息)。虽然我相信你知道你在做什么,你给我们的数字确实是正确的,但对我来说,所有证据都指向人为错误……请仔细检查,在所有情况下,你确实上传了相同的文件。

您最初是如何获得649305字节的?谁给了你那个号码?是你的代码,还是你实际上查看了磁盘上的文件,看看它有多大?在这种情况下,压缩讨论有意义的唯一方法是,如果649305字节是本地运行时文件的大小已经压缩(磁盘上的实际大小为1189763字节),并且实际上,由于某种原因,在部署到AWS时未启用压缩,并且您收到了完整的未压缩文件(我们甚至不知道您如何部署它...它真的和当地一样吗?在这两种情况下,您是否正在运行独立.jar?您是否正在将 .war 部署到 AWS?在这两种情况下,您是否真的在同一容器和容器版本中运行应用程序,或者您可能在本地运行Tomcat,在AWS上运行Jetty?等等等等)。您是否确定您的Postman请求没有搞砸,并且您没有意外发送其他内容(或比您想象的更多)?

编辑:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>com.sandbox</groupId>
    <artifactId>spring-boot-file-upload</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
package com.sandbox;

import static org.springframework.http.ResponseEntity.ok;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@SpringBootApplication
public class Application {

    public static void main(final String[] arguments) {
        SpringApplication.run(Application.class,
                              arguments);
    }

    @RestController
    class ImageRestController {

        @PostMapping(path = "/images")
        ResponseEntity<String> upload(@RequestParam(name = "file") final MultipartFile image) {
            return ok("{\"response\": \"Uploaded image having a size of '" + image.getSize() + "' byte(s).\"}");
        }
    }
}

这个例子是用Java编写的,因为它放在一起的速度更快(环境是一个简单的Java环境,部署了独立的.jar - 没有额外的配置或任何东西,除了服务器端口在5000上)。无论哪种方式,您都可以通过向 http://test123456.us-east-1.elasticbeanstalk.com/images 发送POST请求来亲自尝试一下。

这是我的邮差请求和使用您提供的图像的响应:

在我的AWS EB实例上,一切看起来都很好,所有的数字加起来都和预期的一样。如果你说你的设置听起来很简单,那么不幸的是我和你一样困惑。我只能假设,到目前为止,您已经共享了更多内容(然而,我怀疑这个问题与Spring Boot有关……那么它更有可能与您的AWS配置/设置有关)。

戚奇略
2023-03-14

经过更多的调试,我发现当我直接发布到EC2实例时,一切都按预期工作。我们的主 API 和公有 API URL 通过 Amazon 的 API Gateway 服务发出代理请求。出于某种原因,此服务将数据转换为 Base64,而不仅仅是传递原始二进制数据。

我在这里找到了更新API网关以传递二进制数据的文档。

我使用的是多部分/表单数据的内容类型值。不要忘记在启用二进制支持的API设置中添加它。

最后,不要忘记部署您的api更改...

它现在像预期的那样工作。

 类似资料:
  • 我正在用Spring Boot 2.1.3(使用标准的Tomcat嵌入式web服务器)开发一个endpoint来上载图像,我想限制多部分上载的大小。我可以通过以下属性轻松完成此操作: 但是我总是得到Spring无法捕获的500,因为Tomcat正在抛出异常并且请求无法到达我在RestController中的代码。 我的ExceptionHandler是这样的,但无论注释中出现什么异常,它显然都不起

  • 我试图创建一个页面,用户可以张贴图像及其细节。现在,当我测试来自postman的spring boot服务时,我能够成功地在服务中获取文件。当我试图从angular5中做同样的事情时,多部分文件在服务中没有被识别,并且总是得到空数组。 我的角服务代码如下 } 我已经尝试添加标头,如multipart/form-data,并将其设置为un定义。无论哪种方式,我都收到了错误。在发布到这里之前,我已经广

  • 我正在尝试将图像作为广告中的字符串字段上传,但当将文件添加到正文时,我遇到了这个错误:“异常”:“org.springframework.web.multipart.support.MissingServletRequest estPartException”,“消息”:“所需的请求部分'file'不存在”。我在这里寻找有关此问题的答案,但没有任何帮助。我将很高兴得到任何帮助。 我的控制器: 我的

  • Im使用Spring Boot,并希望使用控制器接收多部分文件上传。当发送文件时,我一直得到错误415不支持的内容类型响应,并且控制器从未到达 我尝试在HTML/JSP页面和使用RESTTemplate的独立客户端应用程序中使用Form:Action发送。所有尝试的结果都是一样的 从multipart文档看来,边界参数必须添加到multipart上载,但这似乎与控制器接收不匹配 我的控制器方法设置

  • 关于Spring MVC应用程序中的多部分文件上传问题,我已经看到了很多关于stackoverflow的答案。我一步一步地确保我不会重复别人犯过的错误。 这是我的表格 在pom文件中我有依赖项 因此,当我停在调试器中时,request对象显示文件已被接收,甚至存储在jBoss临时文件夹中,我并不感到惊讶。 你能指出Spring看不到上传的文件我会错过什么吗?

  • 您可以使用基于浏览器的上传(不是多部分上传)中的内容长度范围字段来限制文件大小:http://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html 你怎么能在多部分上传中限制它?我正在使用EvaporateJS。