-
Notifications
You must be signed in to change notification settings - Fork 38.5k
Support Custom Headers for Multipart Async Data [SPR-16376] #20922
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Arjen Poutsma commented There are two possible ways to accomplish this:
|
Marc-Christian Schulze commented I'm afraid your outlined workaround does not work as expected. Publisher<ByteBuffer> publisher = ...
MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.asyncPart("file", publisher, ByteBuffer.class).header("filename", fileName);
WebClient
.create(url)
.post()
.uri("some-uri")
.body(BodyInserters.fromMultipartData(builder.build()))
.retrieve() The HTTP-Header gets written to the netty stack and flushed. Afterwards I can see the boundary to be written as well followed by the custom headers provided but then the actual part's content is not written. Instead the connection times out. When looking in the Pull Request providing the backing implementation for Publishers the reason becomes clear: if (httpEntity instanceof MultipartBodyBuilder.PublisherEntity<?, ?>) {
MultipartBodyBuilder.PublisherEntity<?, ?> publisherEntity = (MultipartBodyBuilder.PublisherEntity<?, ?>) httpEntity;
resolvableType = publisherEntity.getResolvableType();
} The MultipartHttpMessageWriter expects the Publisher to be wrapped in a PublisherEntity which is the case when the part is created by the BodyInserters.fromMultipartAsyncData() method. But when I use the above-mentioned approach, the part is wrapped in a HttpEntity. I guess the same check for PublisherEntity has to be put in place at DefaultMultipartInserter: @Override
public MultipartInserter with(MultiValueMap<String, Object> values) {
Assert.notNull(values, "'values' must not be null");
for (Map.Entry<String, List<Object>> entry : values.entrySet()) {
for (Object value : entry.getValue()) {
// I guess at this point we should check whether we have to call builder.asyncPart() - in case we got a PublisherEntity
this.builder.part(entry.getKey(), value);
}
}
return this;
} |
Marc-Christian Schulze commented The outlined workaround is not working as expected, unfortunately. |
Marc-Christian Schulze commented Providing the file's content via a Resource is not possible in my case as I receive the file's content asynchronously and I just want to pass the file's content to the http request without caching in-memory or on disk. |
Arjen Poutsma commented Marc-Christian Schulze Can you tell me where the |
Arjen Poutsma commented Fixed in 646fcc5 We now check if there is no Content-Disposition header present before adding a default one. See the test case included in that commit to see how you can set a custom Content-Disposition. |
Marc-Christian Schulze commented I can confirm that with your change it's now possible to set the Content-Disposition when using a Publisher. |
Marc-Christian Schulze opened SPR-16376 and commented
In order to upload a file using the newly introduced method (cf. #20854)
it's necessary to specify the filename and content type along with the publisher.
Right now when streaming asynchronously file content into a multipart request
the resulting http request looks like:
As you can see the file name and the content type is not specified. For a correct file upload I would expect the http request to look like:
Affects: 5.0.2
Issue Links:
Referenced from: commits 646fcc5, 283811b
The text was updated successfully, but these errors were encountered: