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

带有多部分文件的spring Webflux 415

葛深
2023-03-14

我目前正在尝试上传一个文件从一个Angular 4前端到一个spring Webflux控制器。控制器能够读取@RequestPart值,但抛出415 UnsupportedMediaTypeStatusException。

上载控制器

@PostMapping( consumes = MediaType.MULTIPART_FORM_DATA_VALUE )
public Mono<Void> save(@RequestPart("file")MultipartFile file) {
    log.info("Storing a new file. Recieved by Controller");
    this.storageService.store(file);
    return Mono.empty();
}

log.info()方法没有执行,因此似乎是在执行该方法之前抛出了错误。

错误信息

org.springframework.web.server.UnsupportedMediaTypeStatusException: Response status 415 with reason "Content type 'image/png' not supported"
at org.springframework.web.reactive.result.method.annotation.AbstractMessageReaderArgumentResolver.readBody(AbstractMessageReaderArgumentResolver.java:206) ~[spring-webflux-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.web.reactive.result.method.annotation.AbstractMessageReaderArgumentResolver.readBody(AbstractMessageReaderArgumentResolver.java:124) ~[spring-webflux-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.springframework.web.reactive.result.method.annotation.RequestPartMethodArgumentResolver.lambda$resolveArgument$0(RequestPartMethodArgumentResolver.java:99) ~[spring-webflux-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:118) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:450) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:76) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:450) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:67) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:450) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drainAsync(FluxFlattenIterable.java:391) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.drain(FluxFlattenIterable.java:633) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.onNext(FluxFlattenIterable.java:238) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:450) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:87) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:450) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxReplay$SizeBoundReplayBuffer.replayFused(FluxReplay.java:865) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxReplay$SizeBoundReplayBuffer.replay(FluxReplay.java:895) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.ReplayProcessor.onNext(ReplayProcessor.java:436) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.MonoProcessor.drainLoop(MonoProcessor.java:504) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.MonoProcessor.onNext(MonoProcessor.java:347) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:450) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:67) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:450) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:115) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onNext(FluxOnAssembly.java:450) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1069) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.MonoCollect$CollectSubscriber.onComplete(MonoCollect.java:142) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxOnAssembly$OnAssemblySubscriber.onComplete(FluxOnAssembly.java:460) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxCreate$BaseSink.complete(FluxCreate.java:404) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxCreate$BufferAsyncSink.drain(FluxCreate.java:712) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxCreate$BufferAsyncSink.complete(FluxCreate.java:666) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxCreate$SerializedSink.drainLoop(FluxCreate.java:221) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxCreate$SerializedSink.drain(FluxCreate.java:192) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at reactor.core.publisher.FluxCreate$SerializedSink.complete(FluxCreate.java:187) ~[reactor-core-3.1.5.RELEASE.jar:3.1.5.RELEASE]
at org.springframework.http.codec.multipart.SynchronossPartHttpMessageReader$FluxSinkAdapterListener.onAllPartsFinished(SynchronossPartHttpMessageReader.java:215) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE]
at org.synchronoss.cloud.nio.multipart.NioMultipartParser.allPartsRead(NioMultipartParser.java:603) ~[nio-multipart-parser-1.1.0.jar:na]
at org.synchronoss.cloud.nio.multipart.NioMultipartParser.write(NioMultipartParser.java:449) ~[nio-multipart-parser-1.1.0.jar:na]
at org.synchronoss.cloud.nio.multipart.NioMultipartParser.write(NioMultipartParser.java:370) ~[nio-multipart-parser-1.1.0.jar:na]
at org.springframework.http.codec.multipart.SynchronossPartHttpMessageReader$SynchronossPartGenerator.lambda$accept$0(SynchronossPartHttpMessageReader.java:136) ~[spring-web-5.0.4.RELEASE.jar:5.0.4.RELEASE]

spring Webflux应该使用org.synchronoss.cloud.nio.multipart的依赖项已经加载,所以我不完全理解为什么spring会抛出415错误。

我在spring使用WebClient创建了一个测试

WebTest

    @Test
public void sendValidFileSaveCorrectly() {
    MockMultipartFile file = new MockMultipartFile("foo", "foo.txt",
            MediaType.TEXT_PLAIN_VALUE, "Hello World".getBytes());
    MultipartBodyBuilder builder = new MultipartBodyBuilder();
    builder.part("file", file);

    webClient.post()
            .uri("/api/file")
            .syncBody(builder.build())
            .exchange()
            .expectStatus().is2xxSuccessful();
}

使用MockMultipartFile和以下消息,我得到了一个新的500错误

I/O failure: org.springframework.core.codec.CodecException: Type definition error: [simple type, class java.io.ByteArrayInputStream]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class java.io.ByteArrayInputStream and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: org.springframework.mock.web.MockMultipartFile["inputStream"])

我试图理解的是,为什么spring抛出了一个不受支持的媒体类型异常,以及我如何能够指导spring Webflux忽略任何正在编写该响应的内容。

更新

尝试将控制器更改为使用@RequestParams和@RequestBody,但得到相同的415错误。正在处理Multipart请求,但所附文件的内容类型是执行415的内容类型。

我继续向控制器添加了一个ExceptionHandler来尝试捕获UnsupportedMediaTypeStatusException。我无法将文件传递给ExceptionHandler,所以这没有起作用。我可以重写UnsupportedMediaTypeStatusException的默认ExceptionHandler,但如果可能,我更希望避免这样做。

如果它是有用的,我是张贴我的角服务,正在上传文件。然而,因为即使在测试中也会出现错误,所以我不认为Angular有问题。

upload.service.ts

post(file: File, fileName: string) {
const formData = new FormData();
formData.append('file', file, fileName);

let headers = new HttpHeaders();
headers = headers.delete('Content-Type');

this.http
  .post(this.API_URL, formData, { headers: headers, reportProgress: true })
  .subscribe();

}

共有2个答案

丁和歌
2023-03-14

您必须使用Flux或Mono作为多部分上传的类型。https://github.com/hantsy/spring-reactive-sample/blob/master/multipart/src/main/Java/com/example/demo/multipartcontroller.Java

壤驷鸿祯
2023-03-14

请使用@requestpart(“file”)mono 文件 @requestpart(“file”)flux 而不是@requestpart(“file”)MultipartFile文件

@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Mono<Void> save(@RequestPart("file") Mono<FilePart> file) {
        log.info("Storing a new file. Recieved by Controller");
        this.storageService.store(file);
        return Mono.empty();
    }
 类似资料:
  • 我正在尝试将数据从应用程序上传到Spring后端服务。要上传的内容是一个DataModel,其中包含要创建的对象的数据和链接到数据的几个图像。因此,我使用此方法签名: 我尝试使用注释,但要么得到一个空白的图像数组,要么助手为空。你将如何解决这个问题? 提前谢谢。

  • 问题内容: 我想使用Spring MVC发布带有一些JSON数据的文件。因此,我开发了一项休息服务 当我从其他客户端发送请求时 ,出现下一个异常: 谁能帮助我解决这个问题? 我可以同时将Multipart和JSON发送到服务器吗? 问题答案: 这就是我使用JSON数据实现Spring MVC Multipart Request的方式。 带有JSON数据的分段请求(也称为混合分段): 基于Sprin

  • 我有一个源代码,它读取文本文件并存储到一个元组类型的向量中: 包含以下数据: 因此数据由空格+垂直线+空格(多重分隔符)分隔。 如何更改源代码以处理多个分隔符? 注意:如果数据仅用空格隔开,则程序可以工作。

  • 我正在Spring controller中努力实现多部分文件上传。我读过很多问题,谷歌,但似乎什么都不管用。 我明白了 我的BE控制器: FE,angularJS: HTML: 还有应用程序。属性包括: 更新: 当我按照@Byeon0gam的建议从我的控制器中删除@RequestParam时,我不再会遇到这个错误,但是我的文件在控制器中是空的。虽然在FE服务中,如我所见,它不是空的:

  • 有没有办法将文件对象转换为多部分文件?以便我可以将该对象发送到接受接口对象的方法?

  • 问题内容: 我正在将Spring MVC(3.0)与注释驱动的控制器一起使用。我想为资源创建REST-FUL网址,而且能够 不 要求(但仍可选允许)的URL的末尾文件扩展名(但如果没有扩展假设HTML内容类型)。只要文件名部分中没有点(句点/句号),它就可以与Spring MVC一起使用。 但是,我的某些URL要求名称中带有点的标识符。例如: 在这种情况下,Spring会为扩展寻找内容类型,但没有