Skip to content

resttemplate multipart post with InputStreamResource not working [SPR-13571] #18147

Closed
@spring-projects-issues

Description

@spring-projects-issues

Greg Adams opened SPR-13571 and commented

I've been trying to send a multipart post via restTemplate and have been unable to get it to work with anything but FileSystemResource. In my use case (a weird file-forwarding use case) this forces me to copy a MultiPartFile InputStream into a temp file in order be able to create a FileSystemResource, which seems undesirable.

Here's a testing version of the file-receiving controller (from another project, running in another servlet container):

@RestController
public class FileReceiveController {
	
	private Log log = LogFactory.getLog(FileReceiveController.class);

	@RequestMapping(method = RequestMethod.POST)
	public void uploadFile(@RequestParam("customerId") int customerId, @RequestPart("file") MultipartFile multipartFile) {
		log.info("customerId: " + customerId);
		log.info("Received multipart file - original filename: " + multipartFile.getOriginalFilename());
		log.info("content-type: " + multipartFile.getContentType());
		log.info("size: " + multipartFile.getSize());
	}
}

Here's the file-forwarding controller:

@RestController
public class FileForwardController {
	
	private RestTemplate restTemplate;
	
	public FileForwardController() {
		SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
		requestFactory.setBufferRequestBody(false);
		this.restTemplate = new RestTemplate(requestFactory);
	}

	@RequestMapping(method = RequestMethod.POST)
	public void uploadFile(@RequestParam("customerId") int customerId, @RequestPart("file") MultipartFile multipartFile) {
		MultiValueMap<String,Object> parts = new LinkedMultiValueMap<>();
		parts.add("customerId", customerId);
		try {
			// copy to temp file and use FileSystemResource
//			File tempFile = File.createTempFile("xyz", "");
//			FileCopyUtils.copy(multipartFile.getInputStream(), new FileOutputStream(tempFile));
//			parts.add("file", new FileSystemResource(tempFile));
			// OR use InputStreamResource (broken)
			parts.add("file", new InputStreamResource(multipartFile.getInputStream()));
			// OR use ByteArrayResource (broken)
//			parts.add("file", new ByteArrayResource(multipartFile.getBytes()));
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
		HttpHeaders headers = new HttpHeaders();
		headers.setContentType(MediaType.MULTIPART_FORM_DATA);
		HttpEntity<MultiValueMap<String,Object>> request = new HttpEntity<>(parts, headers);
		restTemplate.exchange("http://localhost:8080", HttpMethod.POST, request, Void.class);
	}
}

In this form, the restTemplate.exchange call throws

org.springframework.web.client.HttpClientErrorException: 400 Bad Request
	at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91)
	at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:614)
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:570)

The ByteArrayResource form does the same thing. Only the FileSystemResource form works.


Affects: 4.1.7

Issue Links:

Referenced from: commits 27c1280

0 votes, 6 watchers

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions