我有一个端点,该端点将图像文件上传到服务器,然后上传到S3。
当我在localhost上运行时,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字节,但是当上传到我的产品服务器时,其读数为1189763字节。
我进行了另一项测试,将上传的文件写入服务器,以便进行比较。
十六进制编辑器中上传文件的前n个字节:
EFBFBD50 4E470D0A 1A0A0000 000D4948 44520000 03000000 02400802 000000EF BFBDCC96 01000000 0467414D 410000EF BFBDEFBF BD0BEFBF BD610500 00002063 48524D00 007A2600
原始文件的前n个字节:
89504E47 0D0A1A0A 0000000D 49484452 00000300 00000240 08020000 00B5CC96 01000000 0467414D 410000B1 8F0BFC61 05000000 20634852 4D00007A 26000080 840000FA 00000080
它们看上去都包含文本“ 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只是一个自定义的名称。还有其他涉及休眠模型的代码,但并不相关。
更新
这似乎与Https / api代理相关。当我点击EC2节点的http url时,它工作正常。但是,当我通过代理到EC2节点的api代理(https://api.thedomain.com)时,它将失败。我将继续这条路。
答案 0 :(得分:0)
对不起,但是很多评论都没有道理。 file.size
将返回上传文件的大小(以字节为单位),而不是请求的大小(是的,由于不同的过滤器可能会通过附加信息来增加大小并增加大小)。 Spring不仅可以神奇地将PNG文件的大小增加一倍(在您的情况下,在发送的所有内容的基础上再增加近600kb的信息)。尽管我想相信您知道自己在做什么,并且给我们的数字确实是正确的,但对我来说,所有证据都表明人为错误...请两次,三次,四次检查您确实在所有情况下都上传相同的文件。
首先您是如何获得649305字节的?谁给你这个号码?是您的代码,还是您实际上在查看磁盘上的文件,看看它有多大?在这种情况下,压缩讨论才有意义的唯一方法是,如果在本地运行时649305字节是文件的已压缩大小(其在磁盘上的实际大小为1189763字节),并且实际上在某些情况下部署到AWS时未打开压缩原因,您会收到完整的未压缩文件(我们甚至不知道您是如何部署的...它是否与本地真正相同?两种情况下都运行独立的.jar吗?是否要将.war部署到AWS两种情况下,您是否真的在同一容器和容器版本中运行该应用程序,或者您是在本地运行Tomcat,还是在AWS上运行Jetty?等等,等等。您确定您的邮递员请求没有被搞乱,并且不是偶然发送了其他东西(或超出您的想像)吗?
编辑:
<?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中使用,因为它放在一起的速度更快(该环境是部署了独立.jar的简单Java环境-除了服务器端口位于5000
之外,没有任何额外的配置或任何操作) 。无论哪种方式,您都可以通过向POST
发送http://test123456.us-east-1.elasticbeanstalk.com/images
请求来自己尝试一下
这是我的邮递员要求,并使用您提供的图像进行了回复:
在我的AWS EB实例上,一切似乎都很好,并且所有数字加起来均符合预期。如果您说您的设置听起来很简单,那么不幸的是,我和您一样困惑。我只能假设到目前为止您共享的内容还有更多(但是,我怀疑问题与Spring Boot有关...那么,它很有可能与您的AWS configs / setup有关)。
答案 1 :(得分:0)
经过更多调试后,我发现当我直接发布到EC2实例时,一切都会按预期进行。我们的主要和公共api URL通过Amazon的API网关服务发出代理请求。由于某种原因,此服务会将数据转换为Base64,而不是仅传递原始二进制数据。
我找到了将API网关更新为通过二进制数据的文档:here。
我正在使用multipart/form-data
的Content-Type值。别忘了还要在启用二进制支持的“ API设置”中添加它。
我不必编辑标题选项,另外,我使用了默认的“方法请求传递”模板。
最后,不要忘记部署您的api更改...
它现在按预期运行。
答案 2 :(得分:0)
CloudFormation Template代码段,以实现Kenny Cason的解决方案:
MyApi:
Type: AWS::Serverless::Api
Properties:
BinaryMediaTypes:
- "multipart/form-data"